Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
19.84% covered (danger)
19.84%
1847 / 9310
8.42% covered (danger)
8.42%
8 / 95
CRAP
0.00% covered (danger)
0.00%
0 / 1
WaitingController
19.78% covered (danger)
19.78%
1840 / 9303
8.42% covered (danger)
8.42%
8 / 95
3964006.76
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
1
 checkHash
0.00% covered (danger)
0.00%
0 / 92
0.00% covered (danger)
0.00%
0 / 1
6
 index
65.54% covered (success)
65.54%
194 / 296
0.00% covered (danger)
0.00%
0 / 1
244.24
 checkProperProfile
40.00% covered (warning)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 detail
69.63% covered (success)
69.63%
658 / 945
0.00% covered (danger)
0.00%
0 / 1
2344.47
 getStrengthRating
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 getLessonHistory
90.32% covered (success)
90.32%
56 / 62
0.00% covered (danger)
0.00%
0 / 1
23.48
 getPrimaryDetails
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
6
 getFavCount
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
5
 getAlbum
97.83% covered (success)
97.83%
45 / 46
0.00% covered (danger)
0.00%
0 / 1
5
 arrangeTeacherRecommendList
0.00% covered (danger)
0.00%
0 / 71
0.00% covered (danger)
0.00%
0 / 1
812
 checkReservation
88.46% covered (success)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
10.15
 start
76.92% covered (success)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
12.49
 teacherReserveList
89.21% covered (success)
89.21%
339 / 380
0.00% covered (danger)
0.00%
0 / 1
127.76
 updateChapterOptions
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 result
97.64% covered (success)
97.64%
124 / 127
0.00% covered (danger)
0.00%
0 / 1
7
 loadMoreComments
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
1 / 1
25
 output
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 isCanCancel
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
 convertString
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getTextbookOption
100.00% covered (success)
100.00%
85 / 85
100.00% covered (success)
100.00%
1 / 1
12
 getAllTextbookOption
0.00% covered (danger)
0.00%
0 / 330
0.00% covered (danger)
0.00%
0 / 1
13110
 saveTextbookPreset
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
272
 callLessonAlertandStartButton
0.00% covered (danger)
0.00%
0 / 576
0.00% covered (danger)
0.00%
0 / 1
89102
 loadMoreSelfReviews
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 getUserReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 getReserveAndCancelled
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
 triggerOrangeButton
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 deleteLessonOnair
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
110
 getTeacherOnlineList
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 getSearchCondition
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
6
 getApologyList
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
2
 limitwarning
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 updatedScheduleColor
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 getAvatarDisabledDates
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 sp_counselor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 counselor
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 1
1260
 customersupport
0.00% covered (danger)
0.00%
0 / 152
0.00% covered (danger)
0.00%
0 / 1
756
 counselingGetDisabledDates
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 counselorSlots
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
2070
 avatarSlots
0.00% covered (danger)
0.00%
0 / 219
0.00% covered (danger)
0.00%
0 / 1
4290
 counselingLimit
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
506
 avatarLimit
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 checkCounselingReservationNow
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
110
 spDetail
0.00% covered (danger)
0.00%
0 / 262
0.00% covered (danger)
0.00%
0 / 1
1892
 spAvatarDetail
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 1
702
 avatar_detail
0.00% covered (danger)
0.00%
0 / 629
0.00% covered (danger)
0.00%
0 / 1
21170
 getTeacherReviews
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
870
 favoriteTextbookCategoryForReview
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 teacherAvatarStatus
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 checkMaintenanceForAlert
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
20
 isAvatar
65.22% covered (success)
65.22%
15 / 23
0.00% covered (danger)
0.00%
0 / 1
24.47
 counselorLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 139
0.00% covered (danger)
0.00%
0 / 1
20
 avatarLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 1
42
 userAvailPopularTeacher
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 userValidForSSBEDT
80.00% covered (success)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
5.20
 loadLiveLessonTeacher
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
756
 sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 avatar_sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 checkCounselorTeacherButtonStatus
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 emergencyLesson
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 teacherBadgeList
0.00% covered (danger)
0.00%
0 / 83
0.00% covered (danger)
0.00%
0 / 1
272
 avatarBadgeList
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
272
 teacherOccupation
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 teacherFeatures
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 getSelfReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getGenerationRating
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 getGenerationRatingAPI
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 getUserMemo
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
30
 getReservationCancellationBreakdown
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getActiveCampaign
0.00% covered (danger)
0.00%
0 / 535
0.00% covered (danger)
0.00%
0 / 1
21756
 getActiveCampaignStampData
0.00% covered (danger)
0.00%
0 / 177
0.00% covered (danger)
0.00%
0 / 1
272
 showCampaignModal
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 generateTextbookTeacherRecommendAjax
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 setUpAppreciationSelectionModalElementAjax
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 sendTeacherAppreciationAjax
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
420
 ajaxUpdateSystemTrouble
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
 reportProblem
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
156
 getApppreciationModal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
72
 getAppreciationStatus
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getEvaluationDetail
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 resetLessonReviewModal
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 finishOnlineLesson
0.00% covered (danger)
0.00%
0 / 272
0.00% covered (danger)
0.00%
0 / 1
7310
 getCounselorLessonHistory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
342
 speakingTestAttendance
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
42
 getRegion
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 getResidenceData
29.17% covered (danger)
29.17%
7 / 24
0.00% covered (danger)
0.00%
0 / 1
45.54
 countTeacherReservedLessons
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getLiveCouponResult
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 checkLessonStartButtonNormal
0.00% covered (danger)
0.00%
0 / 671
0.00% covered (danger)
0.00%
0 / 1
112560
 checkLessonStartButtonAvatar
0.00% covered (danger)
0.00%
0 / 653
0.00% covered (danger)
0.00%
0 / 1
94556
 checkLessonStartButtonCounselor
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
30
 checkLessonStartButtonCS
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
 updateLessonSystemTrouble
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 setAppreciationModalFinish
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3App::uses('AppController', 'Controller');
4App::uses('MyPageController', 'Controller');
5App::uses('SpTeacherController', 'Controller');
6App::uses('myArray', 'Lib');
7App::import('Controller', 'Textbook');
8App::uses('AwsFileServer', 'Lib');
9App::uses('Sanitize', 'Utility');
10
11class WaitingController extends AppController{
12    public $uses = array(
13        'Teacher',
14        'LessonOnair',
15        'LessonSchedule',
16        'LessonScheduleCancel',
17        'LessonLog',
18        'User',
19        'UsersDetail',
20        'UsersCourses',
21        'UsersTicket',
22        'UsersPoint',
23        'ShiftWorkOff',
24        'ShiftWorkOn',
25        'UsersClassEvaluation',
26        'UsersLessonsCountMinus',
27        'DefineMaster',
28        'UsersFavorite',
29        'UserTable',
30        'TeacherFeature',
31        'UsersLastViewedTextbook',
32        'TeacherImage',
33        'TeacherStatus',
34        'TextbookCategory',
35        'Payment',
36        'TextbookCourseConnect',
37        'CountryCode',
38        'PhoneVerifyCheckLog',
39        'CommonTeacherStatus',
40        'LessonOnairsLog',
41        'Textbook',
42        'TeacherBadge',
43        'TeacherCourseBadge',
44        'ShiftWorkHideDate',
45        'UsersFavorite',
46        'CounselingTable',
47        'Counseling',
48        'TeacherDetail',
49        'Timezone',
50        'TeacherWeeklyRating',
51        'PopularTeacherCampaignPeriod',
52        'BlockList',
53        'Avatar',
54        'HomeBasedRankBasicAmountLog',
55        'HomeBasedRankBasicAmount',
56        'UsersMemo',
57        'GlobalTextbookCategory',
58        'TeacherRankCoin',
59        'UserTextbookFavorite',
60        'UserSearchCondition',
61        'UsersTextbookInfo',
62        'Corporate',
63        'TeacherStudentConnection',
64        'TextbookConnect',
65        'TeacherStudentConnection',
66        'TeacherFeatureRating',
67        'ChatHistory',
68        'TeacherTextbookStat',
69        'LessonOnairsViewer',
70        'FeatureRatingItem',
71        'UsersFavoriteCategoriesTeacher',
72        'LessonOnairsLogTimeExtension',
73        'LessonOnairsViewersLog',
74        'UsersTextbookInfo',
75        'UsersFavoriteCategories',
76        'UserFeatureRatingLastVoted',
77        'TeacherDetails',
78        'UserFirstLesson',
79        'AppreciationMessage',
80        'UsersClassEvaluationFeatureRating',
81        'ViewersClassEvaluation',
82        'TeacherCoinBox',
83        'LessonOnairsLogTable',
84        'LessonBookmark',
85        'CampaignPcBanner',
86        'ReservationCoin',
87        'CountryRegion',
88        'CampaignInstructor',
89        'CampaignTagControl',
90        'ProhibitedWord',
91        'TitleThresholdTeacher',
92        'ViewerFeatureRatingLastVoted',
93        'PlanTeacherCategoryBlock'
94    );
95
96    public $helpers = array('Html', 'Form');
97    public $selfReviewLimit = 10;
98    public $components = array('Cookie'); //NC-3096 add cookie
99    public $defaultMemoryLimit = null;
100    public $blockMemberSettings = [];
101    public function beforeFilter() {
102        parent::beforeFilter();
103        //NC-3096 cookies
104        $this->Cookie->name = 'searchTeacherForm';
105        $this->Cookie->time = 86400 ;  // 1 day
106        $this->Cookie->domain = $_SERVER['SERVER_NAME'];
107
108        $allowActionArr = array(
109            'index',
110            'detail',
111            'avatar_detail',
112            'avatarSlots',
113            'teacherReserveList',
114            'loadMoreComments',
115            'isShiftWorkCancelled',
116            'callLessonAlertandStartButton',
117            'counselor',
118            'sp_counselor',
119            'counselorSlots',
120            'checkCounselingReservationNow',
121            'teacherAvatarStatus',
122            'getTeacherReviews',
123            'loadLiveLessonTeacher',
124            'limitwarning',
125            'isCanCancel',
126            'teacherBadgeList',
127            'teacherOccupation',
128            'teacherFeatures',
129            'getSelfReviews',
130            'getGenerationRating',
131            'getReservationCancellationBreakdown',
132            'getAlbum',
133            'getFavCount',
134            'getLessonHistory',
135            'getStrengthRating',
136            'getGenerationRatingAPI',
137            'avatarBadgeList',
138            'getPrimaryDetails',
139            'finishOnlineLesson',
140            'speakingTestAttendance',
141            'getRegion',
142            'countTeacherReservedLessons',
143            'checkLessonStartButtonNormal',
144            'checkLessonStartButtonAvatar'
145        );
146
147        $phoneNumbers = $this->CountryCode->getCountryCodesWithSmsAuth();
148        $this->set('phoneNumbers', $phoneNumbers);
149
150        $this->Auth->allow($allowActionArr);
151        //Timezone timedifference
152        $this->set('timeDiffSecond', $this->timeDiffSecond);
153        $this->defaultMemoryLimit = ini_get("memory_limit");
154        $this->blockMemberSettings = $this->PlanTeacherCategoryBlock->getPlanTeacherCategoryBlock($this->sharedUserData['User']);
155    }
156
157    private function checkHash($table , $chatHash) { //returns data if chat_hash exist
158        $fields = array(
159            $table.'.id',
160            $table.'.teacher_id',
161            $table.'.user_id',
162            $table.'.start_time',
163            $table.'.end_time',
164            $table.'.lesson_type', // NC-3824
165            $table.'.lesson_finish', // NC-3824,
166            $table.'.created', // NC-3824
167            $table.'.user_agent',
168            $table.'.lesson_system_trouble',
169            $table.'.connect_id', // NC-5884
170            $table.'.live_lesson_flg',
171            $table.'.connect_id',
172            $table.'.lesson_schedule_id',
173            $table.'.counselor_flag',
174            $table.'.textbook_category_id',
175            'teacher.id',
176            'teacher.name',
177            'teacher.jp_name',
178            'teacher.image_url',
179            'teacher.home_flg', // NC-3824
180            'teacher.rank_coin_id', // NC-3824
181            'teacher.first_lesson_date', // NC-3824
182            'teacher.promote_date', // NC-3824
183            'TeacherDetail.referrer_id', // NC-3824
184            'teacher.counseling_flg', //NC-4589
185            'teacher.avatar_id',
186            'teacher.avatar_flg',
187            'teacher.avatar_parent_flg',
188            'User.nickname',
189            'User.created',
190            'User.fail_flg',
191            'User.charge_flg',
192            'User.birthday',
193            'User.birthday_show_flg',
194            'Connect.id',
195            'Connect.category_id',
196            'Connect.textbook_id',
197            'User.network_review_flg',
198            'User.textbook_review_flg',
199            'User.teacher_review_flg',
200            'User.next_textbook_flg',
201            'User.lesson_review_flg'
202        );
203
204        if ($table == 'LessonOnairsLog') {
205            array_push($fields, 'LessonOnairsLog.onair_id');
206        }
207
208        $data = array(  
209        'conditions' => 
210              array(
211                $table.'.chat_hash' => $chatHash
212               ),  
213        'joins' =>
214                  array(
215                    array(
216                        'table' => 'teachers',
217                        'alias' => 'teacher',
218                        'type' => 'left',
219                        'foreignKey' => false,
220                        'conditions' => array(
221                            'teacher.id ='.$table.'.teacher_id'
222                        )
223                    ),        
224                    array(
225                        'table' => 'users',
226                        'alias' => 'User',
227                        'type' => 'left',
228                        'conditions' => array(
229                            'User.id = '.$table.'.user_id'
230                        )
231                    ),
232                    array(
233                        'table' => 'textbook_connects',
234                        'alias' => 'Connect',
235                        'type' => 'left',
236                        'conditions' => array(
237                            'Connect.id = '.$table.'.connect_id'
238                        )
239                    ),
240                    array( // NC-3824
241                        'table' => 'teacher_details',
242                        'alias' => 'TeacherDetail',
243                        'type' => 'left',
244                        'conditions' => array(
245                            'TeacherDetail.teacher_id = '.$table.'.teacher_id'
246                        )
247                    )
248                ),
249
250        'fields' => $fields,                
251        'order' => array($table.'.id' => 'DESC')            
252        );
253
254        return $data;
255    }
256
257    /**
258 * @api {get} /user/:language/waiting index()
259 * @apiName index
260 * @apiGroup Waiting
261 * @apiDescription Retrieves the index page for the waiting area in Native Camp. It returns various information about the user, teachers, and campaigns.
262 *
263 * @apiParam {String} language The language code for the page.
264 * 
265 * @apiSuccess {Object[]} allBanners The list of campaign banners.
266 * @apiSuccess {String} allBanners.id The ID of the banner.
267 * @apiSuccess {String} allBanners.campaign_url The URL of the campaign.
268 * @apiSuccess {String} allBanners.start The start date of the campaign.
269 * @apiSuccess {String} allBanners.end The end date of the campaign.
270 * @apiSuccess {String} allBanners.image_url The image URL of the campaign.
271 * @apiSuccess {String} allBanners.event_tracking_tag The event tracking tag of the campaign.
272 * @apiSuccess {String} allBanners.display_position The display position of the campaign.
273 * @apiSuccess {Object} searchCount The count of saved search conditions.
274 * @apiSuccess {Object} userpoint The user points.
275 * @apiSuccess {String} localizeDir The localization directory.
276 * @apiSuccess {Object} selectOptions The select options for the teacher search.
277 * @apiSuccess {Object} selectOptions.availability The availability options.
278 * @apiSuccess {Object} selectOptions.classification The classification options.
279 * @apiSuccess {String} headtext The head text for the page.
280 * @apiSuccess {Object[]} badges The list of badges.
281 * @apiSuccess {Boolean} isLoggedIn Indicates if the user is logged in.
282 * @apiSuccess {Object} userData The user data.
283 * @apiSuccess {Object} userData.User The user object.
284 * @apiSuccess {String} userData.User.id The ID of the user.
285 * @apiSuccess {String} userData.User.currency_code The currency code of the user.
286 * @apiSuccess {String} userData.User.card_company The card company of the user.
287 * @apiSuccess {Object} userDataObj The user data object.
288 * @apiSuccess {Number} paymentPlanId The payment plan ID of the user.
289 * @apiSuccess {Number} userLang The language ID of the user.
290 * @apiSuccess {Object[]} seriesSpecialArr The list of special series.
291 * @apiSuccess {Object} seriesSelected The selected series.
292 * @apiSuccess {Object} counselor The counselor object.
293 * @apiSuccess {String} counselor.name The name of the counselor.
294 * @apiSuccess {String} counselor.jp_name The Japanese name of the counselor.
295 * @apiSuccess {String} counselor.image_url The image URL of the counselor.
296 * @apiSuccess {String} counselor.country_name The country name of the counselor.
297 * @apiSuccess {Boolean} isHide Indicates if the counselor is hidden.
298 * @apiSuccess {Object[]} favId The list of favorite teacher IDs.
299 * @apiSuccess {Object[]} teacherFavs The list of favorite teachers with colors.
300 * @apiSuccess {Object[]} teacherFavsColors The list of favorite teacher colors.
301 * @apiSuccess {Object[]} avatarActiveId The list of active avatar IDs.
302 * @apiSuccess {Boolean} teddyFav Indicates if the teddy avatar is favorited.
303 * @apiSuccess {Object[]} occupationData The list of teacher occupations.
304 * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
305 * @apiSuccess {Boolean} hideCouselorFromMember Indicates if the counselor information should be hidden from the member.
306 * @apiSuccess {Boolean} is_lite_plan_user Indicates if the user is on a lite plan.
307 * @apiSuccess {Object[]} teacherList The list of teachers.
308 * @apiSuccess {Object[]} regions The list of regions.
309 * @apiSuccess {Object[]} coinData The list of coin data.
310 * @apiSuccess {Object} searchData The search data.
311 * @apiSuccess {Boolean} isLogin Indicates if the user is logged in.
312 * @apiSuccess {Number} savedConditionsCount The count of saved search conditions.
313 * @apiSuccess {Object} preset The preset textbook information.
314 * @apiSuccess {Object} searchCondition The search condition.
315 * @apiSuccess {Object[]} featureFilter The list of feature filters.
316 * @apiSuccess {Object} user The user object.
317 * @apiSuccess {String} user.id The ID of the user.
318 * @apiSuccess {String} user.name The name of the user.
319 * @apiSuccess {String} disconnectionChatHash The disconnection chat hash.
320 * @apiSuccess {Object[]} coins The list of coins.
321 * @apiSuccess {Object} campaignTagSearch The campaign tag search status.
322 *
323 * @apiSuccessExample {json} Success-Response:
324 *     {
325 *         "allBanners": [
326 *             {
327 *                 "id": "1",
328 *                 "campaign_url": "http://example.com/campaign",
329 *                 "start": "2023-12-01",
330 *                 "end": "2023-12-31",
331 *                 "image_url": "http://example.com/image.jpg",
332 *                 "event_tracking_tag": "tag1",
333 *                 "display_position": "top"
334 *             }
335 *         ],
336 *         "searchCount": 5,
337 *         "userpoint": 100,
338 *         "localizeDir": "en",
339 *         "selectOptions": {
340 *             "availability": {...},
341 *             "classification": {...}
342 *         },
343 *         "headtext": "Welcome to the waiting area",
344 *         "badges": [...],
345 *         "isLoggedIn": true,
346 *         "userData": {
347 *             "User": {
348 *                 "id": "123",
349 *                 "currency_code": "USD",
350 *                 "card_company": "Visa"
351 *             }
352 *         },
353 *         "userDataObj": {...},
354 *         "paymentPlanId": 1,
355 *         "userLang": 1,
356 *         "seriesSpecialArr": [...],
357 *         "seriesSelected": {...},
358 *         "counselor": {
359 *             "name": "John Doe",
360 *             "jp_name": "ジョン・ドウ",
361 *             "image_url": "http://example.com/image.jpg",
362 *             "country_name": "Japan"
363 *         },
364 *         "isHide": false,
365 *         "favId": [...],
366 *         "teacherFavs": [...],
367 *         "teacherFavsColors": [...],
368 *         "avatarActiveId": [...],
369 *         "teddyFav": true,
370 *         "occupationData": [...],
371 *         "counselorLampStatus": {...},
372 *         "hideCouselorFromMember": false,
373 *         "is_lite_plan_user": true,
374 *         "teacherList": [...],
375 *         "regions": [...],
376 *         "coinData": [...],
377 *         "searchData": {...},
378 *         "isLogin": true,
379 *         "savedConditionsCount": 5,
380 *         "preset": {...},
381 *         "searchCondition": {...},
382 *         "featureFilter": [...],
383 *         "user": {
384 *             "id": "123",
385 *             "name": "John Doe"
386 *         },
387 *         "disconnectionChatHash": "abc123",
388 *         "coins": [...],
389 *         "campaignTagSearch": {...}
390 *     }
391 *
392 * @apiError {String} status The status of the request (NG).
393 * @apiError {String} message The error message.
394 *
395 * @apiErrorExample {json} Error-Response:
396 *     {
397 *         "status": "NG",
398 *         "message": "Invalid request."
399 *     }
400 * 
401 * @apiSampleRequest off
402 */
403    public function index() {
404        // NJ-37582 redirect to appointment
405        $this->redirect('/appointment');
406        
407        $this->Teacher->hasAfterFind = true;
408        //mobile view only
409        
410        if ($this->RequestHandler->isMobile()) {
411            $this->layout = 'mobile';
412            $userpoints = $this->UsersPoint->getCurrentUserPoint($this->Auth->user('id'));
413
414            myTools::initializeApiTunnel(['SearchConditionsController']);
415
416            $displayRestrictionParams = array(
417                'lang' => $this->localizeDir
418            );
419
420            $searchConditions = new SearchConditionsController();
421            $params= array(
422                "users_api_token" => $this->Auth->user('api_token'),
423                "nc_terminal_type" => Configure::read('nc_terminal_type.pc'),
424                "displayRestrictionParams" => $displayRestrictionParams
425            );
426            $searchConditions->params = $params;
427
428            $search = json_decode($searchConditions->index(), true);
429            $savedSearchCount = count($search['conditions'] ?? []);
430
431            $this->set('searchCount', $savedSearchCount);
432            $this->set('userpoint', $userpoints);
433            $this->set('localizeDir',  $this->localizeDir);
434            return $this->render('/Mobile/Teacher/index');
435        }
436
437        $params = $this->params->query;
438        if (isset($params['stealth'])) {
439            TeacherTable::setStealthSettings($this->Cookie, $params['stealth']);
440        }
441        $selectOptions = array(
442            'availability' => TeacherTable::teacherAvailSelect2(),
443            //'nationality' => TeacherTable::teacherLocationSelect()
444            'classification' => TeacherTable::teacherClassificationSelect()
445        );
446        $this->set('selectOptions', $selectOptions);
447        $this->set('headtext', Configure::read('my.meta.waiting-index.headtext'));
448        $this->set('badges', TeacherBadgeTable::displayBadges());
449        $this->set('isLoggedIn', $this->Auth->loggedIn());
450        
451        $userData = $this->sharedUserData;//use shared user data 
452        // NJ-46: mypage banners
453        $userDataObj = new UserTable($userData['User']);
454        $paymentPlanId = $userDataObj->getMembershipTypeIndex();
455        $userLang = $this->CountryCode->getUserLanguageId($this->localizeDir);
456
457        // - conditions
458        $conditions = array(
459            'CampaignPcBanner.status' => 1,
460            'CampaignPcBannerCurrency.currency_code' => $userData['User']['currency_code'],
461            'CampaignPcBannerLanguage.language_id' => $userLang,
462        );
463
464        if ($userData['User']['card_company']) {
465            $conditions['CampaignPcBanner.payment_company LIKE'] = '%' . $userData['User']['card_company'] . '%';
466        }
467
468        if ($paymentPlanId) {
469            $conditions['FIND_IN_SET(?, CampaignPcBanner.user_status)'] = $paymentPlanId;
470        }
471        $this->log("[CampaignSettingsModal] conditions -> " .  json_encode($conditions), "debug");
472
473        $this->CampaignPcBanner->openDBReplica();
474        $allBanners = $this->CampaignPcBanner->find('all', array(
475            'fields' => array(
476                'CampaignPcBanner.id',
477                'CampaignPcBanner.campaign_url',
478                'CampaignPcBanner.start',
479                'CampaignPcBanner.end',
480                'CampaignPcBanner.image_url',
481                'CampaignPcBanner.event_tracking_tag',
482                'CampaignPcBanner.display_position'
483            ),
484            'conditions' => $conditions,
485            'joins' => array(
486                array(
487                    'table' => 'campaign_pc_banner_currencies',
488                    'alias' => 'CampaignPcBannerCurrency',
489                    'type' => 'LEFT',
490                    'conditions' => array('CampaignPcBannerCurrency.campaign_pc_banner_id = CampaignPcBanner.id')
491                ),
492                array(
493                    'table' => 'campaign_pc_banner_languages',
494                    'alias' => 'CampaignPcBannerLanguage',
495                    'type' => 'LEFT',
496                    'conditions' => array('CampaignPcBannerLanguage.campaign_pc_banner_id = CampaignPcBanner.id')
497                )
498            ),
499            'order' => 'CampaignPcBanner.priority_number ASC',
500            'recursive' => -1,
501        ));
502        $this->CampaignPcBanner->closeDBReplica();
503        $this->set('allBanners', $allBanners);
504
505        //instantiate view
506        $view = new View($this, false);
507        $view->layout = false;
508        //fetch data
509        $this->Teacher->hasAfterFind = true;
510        //NC-4548 from kids text description course
511        if (isset($_COOKIE['fromKidsDescription']) && $_COOKIE['fromKidsDescription'] !== 'null') {
512            $kidsCourseTeacher = array(
513                'sortRadio' => 'status',
514                'statusRadio' => 'all',
515                'teacherFeature' => array(0 => 'kids'),
516                'textbookRadioVal' => '2',
517                'courseOptionSearchCourseId' => '2',
518                'courseOptionChapterId' => '1',
519                'courseOptionLessonTextId' => '209',
520                'courseOptionConnectId' => '1',
521                'seriesOptionSearchTextBookCategoryId' => '11',
522                'badgeIds' => '11'
523            );
524
525            $this->Cookie->write('searchData', $kidsCourseTeacher);
526        }
527
528        //NJ-9440 - add status ALL + Live flg
529        if (isset($this->request->query['from_live_lesson_usage']) && $this->request->query['from_live_lesson_usage'] == 1) {
530            $liveTeachers = array(
531                'sortRadio' => 'status',
532                'statusRadio' => 'all',
533                'searchLiveLesson' => '1'
534            );
535            $this->Cookie->write('searchData', $liveTeachers);
536        }
537
538        if (!class_exists('myMemcached')) {
539            App::uses('myMemcached', 'Lib');
540        }
541        $memcache = new myMemcached();
542        if ($this->Auth->loggedIn()) {
543            $memKey = "searchCallanUsers_{$this->sharedUserData['User']['id']}";
544        } else {
545            $memKey = "searchCallanUsers";
546        }
547        if ($memSearchReserveData = $memcache->get($memKey)) {
548            $this->Cookie->write('searchData', $memSearchReserveData);
549            $memcache->delete($memKey);
550        }
551
552        // NJ-5836
553        $displayRestrictionParams = array(
554            'lang' => $this->localizeDir
555        );
556
557        // get display restriction setting
558        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
559
560        $query = array();
561        if ($this->isStudySapuriUser) {
562            // Get all Book
563            $getAllBookArr = array(
564                'user_id' => $this->Auth->user('id'),
565                'textbook_type' => 2,
566                'arrange_data' => 'trunk',
567                'preset' => 'off',
568                'user_locale' => $this->localizeDir,
569                'load_description' => false
570            );
571            $seriesCategoryData = $this->Textbook->getTextbooks($getAllBookArr);
572            $seriesArr = $seriesCategoryData['res_data'];
573
574            $getSeriesPresetArr = array(
575                'user_id' => $this->Auth->user('id'),
576                'textbook_type' => 2,
577                'select_method' => 'first',
578                'preset' => 'off',
579                'displayRestriction' => $displayRestriction
580            );
581            $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
582            $seriesPreset = $seriesPresetData['res_data'];
583            $seriesId = $seriesPreset['TextbookCategory']['id'];
584            // NC-7228 set series id from saved search condition
585            $searchData = $this->Cookie->read('searchData');
586            if(isset($searchData['seriesOptionSearchTextBookCategoryId']) && !empty($searchData['seriesOptionSearchTextBookCategoryId'])){
587                $seriesId = $searchData['seriesOptionSearchTextBookCategoryId'];
588            }
589            $seriesSelected = isset($seriesArr[$seriesId]) ? $seriesArr[$seriesId] : 0;
590
591            if ($seriesSelected) {
592                $query['badgeIds'] = $seriesSelected;
593            }
594
595            $this->set('seriesSpecialArr', $seriesArr);
596            $this->set('seriesSelected', $seriesSelected);
597        }
598        // - NJ-6390
599        $searchParams = !empty($query) && $query? $query : $this->Cookie->read('searchData');
600        $highLightFlag = null;
601        if (isset($searchParams['keywordText']) && $searchParams['keywordText']) {
602            // - 1 = able to highlight the keyWord freeword search
603            $highLightFlag = 1;
604
605            // -delete session
606            $this->Session->delete('freeword-'.$this->Auth->user('id'));
607
608            // - add session for freewordArray
609            $this->Session->write('freeword-'.$this->Auth->user('id'), $this->request->data['keywordText']);
610        }
611
612        $data = [];
613
614        if (!$this->isStudySapuriUser) {
615            $counselor = $this->Teacher->find('first', array(
616                'fields' => array(
617                    'Teacher.name',
618                    'Teacher.jp_name',
619                    'Teacher.image_url',
620                    'CountryCode.country_name'
621                ),
622                'joins' => array(
623                    array(
624                        'type' => 'LEFT',
625                        'table' => 'country_codes',
626                        'alias' => 'CountryCode',
627                        'conditions' => 'Teacher.homeland2 = CountryCode.id'
628                    )
629                ),
630                'conditions' => array('Teacher.id' => Configure::read('default_counselor_detail')),
631                'recursive' => -1
632            ));
633        }
634
635        # check counselor if hidden
636        $where = array(
637            'user_id' => $this->Auth->user('id'),
638            'teacher_id' => Configure::read('default_counselor_detail')
639        );
640        $isHide = $this->BlockList->isTeacherHide($where);
641        $this->set('isHide', $isHide);
642
643        $favId = $this->Auth->loggedIn() ? $this->UsersFavorite->getTeacherIdList($this->Auth->user('id')) : array();
644//        NJ-10550
645        $teacherFavs = $this->Auth->loggedIn() ?
646            $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => array_values($favId)]) : [];
647        $colors = $this->UsersFavoriteCategoriesTeacher::COLORS;
648        $teacherFavsColors = []; //default
649
650        //-validate array variable
651        if (
652            $teacherFavs && 
653            is_array($teacherFavs)
654        ) {
655            $teacherFavsColors = array_map(function ($val) use ($colors) {
656                $index = array_search($val, array_column($colors, 'code'));
657                return $index >= 0 ? $colors[$index]['hex'] : '#F0295D';
658            }, $teacherFavs);
659        }
660
661        $this->set('teacherFavsColors', $teacherFavsColors);
662        // NC-7031 - avatar teachers
663        $avatarIdArr = array();
664        $teddyFav = false;
665        $getAvatarId = $this->Teacher->getParentAvatarTeacher();
666        if ($getAvatarId) {
667            $avatarIdArr = array_values($getAvatarId);
668
669            if ( $this->Auth->loggedIn() ) { // logged in
670                if ( $favId ) {
671                    // teddy
672                    $favAvaTParams = array(
673                        "avatar_id" => Configure::read('avatar_id.teddy'),
674                        "teacher_id" => $favId,
675                    );
676                    $checkTeddyFav = $this->Teacher->checkFavAvatarTeacher($favAvaTParams);
677
678                    if ($checkTeddyFav) {
679                        $teddyFav = true;
680                    }
681                }
682            }
683        }
684        //NC-9215 get teacher occupation industry and position
685        $this->set('occupationData', ClassRegistry::init('TeacherOccupationDetail')->getActiveOccupation());
686
687        // NJ-20272 : get counselor teacher lamp status
688        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
689
690        // NJ-9489 : check if membership is allowed to display counselor information
691         $_userData = $this->sharedUserData;
692        $hideCouselorFromMember = 0;
693        $n_isLitePlanUser = false;
694        if ($_userData) {
695            $_userPaymentPlan = $_userData['User']['payment_plan_id'];
696  
697            if (
698                  !$_userPaymentPlan ||
699                  in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
700            ) {
701                $hideCouselorFromMember = 1;
702            }
703
704            // NJ-37250 : set lite plan user flag 
705            if ($_userPaymentPlan && in_array($_userPaymentPlan, Configure::read('lite_payment_plans'))) {
706                $n_isLitePlanUser = true;
707            }
708        
709        }
710        $this->set('is_lite_plan_user',$n_isLitePlanUser);
711        $this->set('hideCouselorFromMember',$hideCouselorFromMember);
712
713        $view->set(array(
714            'teddyFav' => $teddyFav,
715            'avatarActiveId' => $avatarIdArr,
716            'counselor' => isset($counselor) ? $counselor : null,
717            'teachers' => isset($data['teacherData']) ? $data['teacherData'] : array(),
718            'counterData' => isset($data['limitGauge']) ? $data['limitGauge'] : 0,
719            'teacherRecordCount' => isset($data['teacherRecordCount']) ? $data['teacherRecordCount'] : 0,
720            'recordCount' => isset($data['teacherData']) ? count($data['teacherData']) : 0,
721            'limitRecord' => isset($data['limit']) ? $data['limit'] : 0,
722            'estimateRecord' => isset($data['limit']) && isset($data['teacherData']) ? count($data['teacherData']) * $data['limit'] : 0, 
723            'messageFlag' => false,
724            'isLoggedIn' => $this->Auth->loggedIn(),
725            'caller' => 'waiting',
726            'favId' => $favId,
727            'userId' => $this->Auth->loggedIn() ? $this->sharedUserData['User']['id'] : '',
728            'isHide' => $isHide,
729            'highLightFlag' => $highLightFlag,
730            'counselorLampStatus' => $counselorLampStatus
731        ));
732        $teacherList = $view->render('/MyPage/online_teachers');
733        $this->set('teacherList', $teacherList);
734
735
736        // NC-9142
737        $badges = $this->Textbook->getPresetTextbookSeriesId();
738
739        $userLangId = $this->CountryCode->getUserLanguageId(!empty($_userData['User']['native_language2']) ? $_userData['User']['native_language2'] : Configure::read('english_language'));
740
741        // - get regions list
742        $this->set('regions', $this->Teacher->getAvailableNationality($this->localizeDir, ($this->isStudySapuriUser ? true : false), ($this->isStudySapuriUser ? $badges : '')), array(), $userLangId); //nationalities of teachers
743        
744        $this->set('coinData', $this->TeacherRankCoin->getCoinAmount()); // set coin dropdown
745        $defaultSearchData = $this->Cookie->read('searchData');
746
747        if (isset($this->request->query['campaign_filter']) && $this->request->query['campaign_filter']) {
748            $campaignFilter = $this->request->query['campaign_filter'];
749            $defaultSearchData['statusRadio'] = 'all';
750            $defaultSearchData['textbookRadioVal'] = 2;
751            $this->Cookie->write('searchReserveData.seriesOptionSearchTextBookCategoryId', Configure::read('campaign_config.'.$campaignFilter.'.ENV.'.Configure::read('ENVIRONMENT').'.textbook_category_id'));
752        }
753        $this->set('searchData', $defaultSearchData);
754        $this->set('isLogin', $this->Auth->loggedIn());
755
756        // NC-7228 get stored search conditions
757        $savedConditionsCount = $this->UserSearchCondition->getSavedConditionsCount($this->sharedUserData['User']['id'], $n_isLitePlanUser);
758        $this->set('savedConditionsCount', $savedConditionsCount);
759
760        // set default preset params
761        $presetParams = array(
762            'user_id' => $this->Auth->user('id'),
763            'lang' => (isset($this->localizeDir) && $this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
764            'is_pc_flg' => 1
765        );
766
767        //
768        if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) && 
769            ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
770          ){
771            $presetParams['userValidForSSBEDT'] = true;
772        }
773
774        //
775        if (isset($this->sharedUserData['User'])) {
776            //
777            $userDataObj = new UserTable($this->sharedUserData['User']);
778
779            //
780            if (!empty($userDataObj->getMembershipTypeIndex())) {
781                $presetParams["userMembershipType"] = $userDataObj->getMembershipTypeIndex();
782            }
783
784            $presetParams['native_language2'] = $userDataObj->native_language2;
785
786        }
787
788        // get preset data
789        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
790
791        //
792        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
793            // for preset
794            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
795            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
796
797        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
798            // use last viewed textbook if no preset data.
799            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
800            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
801
802        }
803
804        // initial fetch preset 
805        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
806
807        // if no preset fetched - unsupported, fetch for tb with sort prioty 1
808        if(!$preset) {
809            unset($presetParams['connect_id']);
810            unset($presetParams['last_opened_date']);
811            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
812        }
813
814        $this->set('preset', $preset);
815        $this->set('searchCondition', $this->Session->read('savedSearchCondition'));
816        //- 
817        $this->set('featureFilter', $this->FeatureRatingItem->getFeatureFilters(['langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)]));
818
819        // - NJ-11223 
820        $oUserData = new UserTable($this->sharedUserData['User']);
821        $this->set('user', $oUserData);
822        $this->Session->delete('savedSearchCondition');
823
824        // NJ-21309
825        $memcached = new myMemcached();
826        $disconnectionChatHash = $memcached->get('disconnectionChatHash');
827        $this->set('disconnectionChatHash', $disconnectionChatHash);
828
829
830        //- NJ-36852
831        $this->ReservationCoin->openDBReplica();
832        $coins = $this->ReservationCoin->find('all', ['conditions'=> array('status' => 1)]);
833        $this->ReservationCoin->closeDBReplica();
834
835          $coinArray = [];
836        if($coins && is_array($coins)) {
837            foreach ($coins as $c) {
838                $coinArray[] = $c['ReservationCoin']['coin'];
839            }
840        } 
841        
842        $this->set("coins", json_encode($coinArray));
843
844        # NJ-19429: Search Campaign Teachers
845        $campaignTagSearch = $this->CampaignTagControl->getCampaignTagStatusPC($this->sharedUserData['User']['id']);
846        $this->set('campaignTagSearch', $campaignTagSearch);
847        
848    }
849
850    private function checkProperProfile($teacherId) {
851        if (!is_numeric($teacherId)) {
852            $this->redirect('/waiting/detail/'.intval($teacherId), '301');
853        } else if (!ctype_digit($teacherId)){
854            $this->log("Invalid [teacher_id] ".$teacherId, "error");
855            throw new NotFoundException();
856        }
857
858        /* commented conflict to localization
859        if (isset($this->params->url) && $this->params->url != 'waiting/detail/'.$teacherId) {
860            $this->redirect('/waiting/detail/'.$teacherId, '301');
861        }*/
862    }
863
864    /**
865     * @api {get} /user/:language/waiting/detail/:teacherId/:highLightFlag detail()
866     * @apiName detail
867     * @apiGroup Waiting
868     * @apiDescription Retrieves the detailed information for a specific teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
869     *
870     * @apiParam {String} language The language code.
871     * @apiParam {String} teacherId The ID of the teacher.
872     * @apiParam {String} [highLightFlag] The highlight flag.
873     * 
874     * @apiSuccess {Object} teacher The teacher object.
875     * @apiSuccess {String} teacher.id The ID of the teacher.
876     * @apiSuccess {String} teacher.name The name of the teacher.
877     * @apiSuccess {String} teacher.image The image URL of the teacher.
878     * @apiSuccess {Object} country The country object.
879     * @apiSuccess {String} country.name The name of the country.
880     * @apiSuccess {String} country.code The code of the country.
881     * @apiSuccess {Object} timezone The timezone object.
882     * @apiSuccess {String} timezone.name The name of the timezone.
883     * @apiSuccess {String} timezone.offset The offset of the timezone.
884     * @apiSuccess {Object} tutorCategory The tutor category object.
885     * @apiSuccess {String} tutorCategory.name The name of the tutor category.
886     * @apiSuccess {Number} timeDiff The time difference in seconds.
887     * @apiSuccess {Object} onair The on-air data.
888     * @apiSuccess {String} onair.id The ID of the on-air data.
889     * @apiSuccess {String} onair.status The status of the on-air data.
890     * @apiSuccess {String} userId The ID of the user.
891     * @apiSuccess {Object[]} series The list of textbook series.
892     * @apiSuccess {String} series.id The ID of the series.
893     * @apiSuccess {String} series.name The name of the series.
894     * @apiSuccess {Object[]} teacherTbRatings The teacher textbook ratings.
895     * @apiSuccess {String} teacherTbRatings.id The ID of the rating.
896     * @apiSuccess {String} teacherTbRatings.rating The rating value.
897     * @apiSuccess {Number} historyYear The number of years of teaching history.
898     * @apiSuccess {Number} historyMonth The number of months of teaching history.
899     * @apiSuccess {Object} teacherStatus1 The teacher status object.
900     * @apiSuccess {String} teacherStatus1.status The status of the teacher.
901     * @apiSuccess {Object} oOnair The on-air object.
902     * @apiSuccess {String} oOnair.id The ID of the on-air object.
903     * @apiSuccess {String} oOnair.status The status of the on-air object.
904     * @apiSuccess {Number} teacherTitleThreshold The teacher title threshold.
905     * @apiSuccess {Number} initialTeacherStatus The initial teacher status.
906     * @apiSuccess {Boolean} isFav Indicates if the teacher is favorited by the user.
907     * @apiSuccess {Boolean} isHide Indicates if the teacher is hidden by the user.
908     * @apiSuccess {Boolean} unsupportedBrowser Indicates if the browser is unsupported.
909     * @apiSuccess {Boolean} canReport Indicates if the user can report the teacher.
910     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
911     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates if it is the user's first time logging in.
912     * @apiSuccess {Boolean} paidParent Indicates if the user is a paid parent.
913     * @apiSuccess {Number} velifyCount The count of phone verification logs.
914     * @apiSuccess {Object[]} countryCodes The list of country codes.
915     * @apiSuccess {String} countryCodes.code The code of the country.
916     * @apiSuccess {String} countryCodes.name The name of the country.
917     * @apiSuccess {Object} userCountry The user's country information.
918     * @apiSuccess {String} userCountry.name The name of the user's country.
919     * @apiSuccess {String} userCountry.code The code of the user's country.
920     * @apiSuccess {Boolean} deviceNotSupported Indicates if the device is not supported.
921     * @apiSuccess {Object} userLang The user's language information.
922     * @apiSuccess {String} userLang.name The name of the user's language.
923     * @apiSuccess {String} userLang.code The code of the user's language.
924     * @apiSuccess {Object} getCRData The country residence data.
925     * @apiSuccess {String} getCRData.country The country of residence.
926     * @apiSuccess {Object} residenceData The residence data.
927     * @apiSuccess {String} residenceData.city The city of residence.
928     * @apiSuccess {Boolean} residenceFlg Indicates if the residence flag is set.
929     * @apiSuccess {Boolean} login Indicates if the user is logged in.
930     * @apiSuccess {Object} preset The preset textbook information.
931     * @apiSuccess {String} preset.id The ID of the preset textbook.
932     * @apiSuccess {String} preset.name The name of the preset textbook.
933     * @apiSuccess {Boolean} presetIsLiveTextbook Indicates if the preset textbook is for live lessons.
934     * @apiSuccess {Object[]} apologyList The list of apologies.
935     * @apiSuccess {String} apologyList.id The ID of the apology.
936     * @apiSuccess {String} apologyList.message The message of the apology.
937     * @apiSuccess {Boolean} isNormalLitePlanUser Indicates if the user is on a normal lite plan.
938     * @apiSuccess {Object} getKeepMemo The keep memo information.
939     * @apiSuccess {String} getKeepMemo.id The ID of the keep memo.
940     * @apiSuccess {String} getKeepMemo.memo The memo text.
941     * @apiSuccess {String} textbookConnectId The textbook connect ID.
942     * @apiSuccess {Number} textbookCategoryTypeId The textbook category type ID.
943     * @apiSuccess {Boolean} highLightFlag Indicates if the highlight flag is set.
944     * @apiSuccess {Number} liveCoin The live lesson coin amount.
945     * @apiSuccess {Number} order The order of the teacher reviews.
946     * @apiSuccess {Object[]} lesson_history_data The lesson history data.
947     * @apiSuccess {String} lesson_history_data.id The ID of the lesson history.
948     * @apiSuccess {String} lesson_history_data.date The date of the lesson history.
949     * @apiSuccess {Boolean} showRating Indicates if the rating should be shown.
950     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation data.
951     * @apiSuccess {Number} reserveAndCancel.reserved The number of reserved lessons.
952     * @apiSuccess {Number} reserveAndCancel.cancelled The number of cancelled lessons.
953     * @apiSuccess {Number} lessonHistoryCount The count of lesson history.
954     * @apiSuccess {Object} latestUserLesson The latest user lesson information.
955     * @apiSuccess {String} latestUserLesson.id The ID of the latest user lesson.
956     * @apiSuccess {String} latestUserLesson.date The date of the latest user lesson.
957     * @apiSuccess {Object} teacherRates The teacher rates.
958     * @apiSuccess {Number} teacherRates.rate The rate of the teacher.
959     * @apiSuccess {String} teacherIdCheck The teacher ID check.
960     * @apiSuccess {String} latestLessonData The latest lesson data.
961     * @apiSuccess {String} teacherLastLogin The last login time of the teacher.
962     * @apiSuccess {Number} teacherFavoriteCount The favorite count of the teacher.
963     * @apiSuccess {Object} teacherFeatures The teacher features.
964     * @apiSuccess {String} teacherFeatures.feature The feature of the teacher.
965     * @apiSuccess {Boolean} validCampaignDate Indicates if the campaign date is valid.
966     * @apiSuccess {Object} campaign The campaign information.
967     * @apiSuccess {String} campaign.id The ID of the campaign.
968     * @apiSuccess {String} campaign.name The name of the campaign.
969     * @apiSuccess {Object[]} ownReservationTeacherData The own reservation teacher data.
970     * @apiSuccess {String} ownReservationTeacherData.id The ID of the reservation.
971     * @apiSuccess {String} ownReservationTeacherData.date The date of the reservation.
972     * @apiSuccess {Number} studentDelayInSeconds The delay in seconds for the student lesson priority.
973     * @apiSuccess {Number} remainingSeconds The remaining seconds for the lesson.
974     * @apiSuccess {Boolean} ownReservationFlg Indicates if the user has their own reservation.
975     * @apiSuccess {String} teacherStatusColor The color of the teacher status.
976     * @apiSuccess {String} chatHash The chat hash.
977     * @apiSuccess {Boolean} liveLessonFlg Indicates if the lesson is a live lesson.
978     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
979     *
980     * @apiSuccessExample {json} Success-Response:
981     *     {
982     *         "teacher": {
983     *             "id": "123",
984     *             "name": "John Doe",
985     *             "image": "http://example.com/image.jpg"
986     *         },
987     *         "country": {
988     *             "name": "Japan",
989     *             "code": "JP"
990     *         },
991     *         "timezone": {
992     *             "name": "JST",
993     *             "offset": "+09:00"
994     *         },
995     *         "tutorCategory": {
996     *             "name": "English"
997     *         },
998     *         "timeDiff": 0,
999     *         "onair": {
1000     *             "id": "456",
1001     *             "status": "active"
1002     *         },
1003     *         "userId": "123",
1004     *         "series": [
1005     *             {
1006     *                 "id": "1",
1007     *                 "name": "Series 1"
1008     *             }
1009     *         ],
1010     *         "teacherTbRatings": [
1011     *             {
1012     *                 "id": "1",
1013     *                 "rating": "5"
1014     *             }
1015     *         ],
1016     *         "historyYear": 2,
1017     *         "historyMonth": 6,
1018     *         "teacherStatus1": {
1019     *             "status": "available"
1020     *         },
1021     *         "oOnair": {
1022     *             "id": "789",
1023     *             "status": "active"
1024     *         },
1025     *         "teacherTitleThreshold": 0,
1026     *         "initialTeacherStatus": 1,
1027     *         "isFav": true,
1028     *         "isHide": false,
1029     *         "unsupportedBrowser": false,
1030     *         "canReport": true,
1031     *         "hideLimitedPlanReservation": false,
1032     *         "firstTimeLoggedIn": false,
1033     *         "paidParent": false,
1034     *         "velifyCount": 1,
1035     *         "countryCodes": [
1036     *             {
1037     *                 "code": "JP",
1038     *                 "name": "Japan"
1039     *             }
1040     *         ],
1041     *         "userCountry": {
1042     *             "name": "Japan",
1043     *             "code": "JP"
1044     *         },
1045     *         "deviceNotSupported": false,
1046     *         "userLang": {
1047     *             "name": "Japanese",
1048     *             "code": "ja"
1049     *         },
1050     *         "getCRData": {
1051     *             "country": "Japan"
1052     *         },
1053     *         "residenceData": {
1054     *             "city": "Tokyo"
1055     *         },
1056     *         "residenceFlg": true,
1057     *         "login": true,
1058     *         "preset": {
1059     *             "id": "1",
1060     *             "name": "Preset Textbook"
1061     *         },
1062     *         "presetIsLiveTextbook": true,
1063     *         "apologyList": [],
1064     *         "isNormalLitePlanUser": true,
1065     *         "getKeepMemo": {
1066     *             "id": "1",
1067     *             "memo": "This is a memo."
1068     *         },
1069     *         "textbookConnectId": "123",
1070     *         "textbookCategoryTypeId": 1,
1071     *         "highLightFlag": true,
1072     *         "liveCoin": 100,
1073     *         "order": 0,
1074     *         "lesson_history_data": [
1075     *             {
1076     *                 "id": "1",
1077     *                 "date": "2023-12-01"
1078     *             }
1079     *         ],
1080     *         "showRating": true,
1081     *         "reserveAndCancel": {
1082     *             "reserved": 10,
1083     *             "cancelled": 2
1084     *         },
1085     *         "lessonHistoryCount": 10,
1086     *         "latestUserLesson": {
1087     *             "id": "1",
1088     *             "date": "2023-12-01"
1089     *         },
1090     *         "teacherRates": {
1091     *             "rate": 5
1092     *         },
1093     *         "teacherIdCheck": "123",
1094     *         "latestLessonData": "2023-12-01 (Fri)",
1095     *         "teacherLastLogin": "01/12/2023 (Fri)",
1096     *         "teacherFavoriteCount": 50,
1097     *         "teacherFeatures": {
1098     *             "feature": "Friendly"
1099     *         },
1100     *         "validCampaignDate": true,
1101     *         "campaign": {
1102     *             "id": "1",
1103     *             "name": "Campaign 1"
1104     *         },
1105     *         "ownReservationTeacherData": [
1106     *             {
1107     *                 "id": "1",
1108     *                 "date": "2023-12-01"
1109     *             }
1110     *         ],
1111     *         "studentDelayInSeconds": 0,
1112     *         "remainingSeconds": 0,
1113     *         "ownReservationFlg": true,
1114     *         "teacherStatusColor": "green",
1115     *         "chatHash": "abc123",
1116     *         "liveLessonFlg": true,
1117     *         "lessonRequestFlg": 1
1118     *     }
1119     *
1120     * @apiError {String} status The status of the request (NG).
1121     * @apiError {String} message The error message.
1122     *
1123     * @apiErrorExample {json} Error-Response:
1124     *     {
1125     *         "status": "NG",
1126     *         "message": "Invalid request."
1127     *     }
1128     * 
1129     * @apiSampleRequest off
1130     */
1131    public function detail($teacherId = null, $highLightFlag = null) {
1132
1133        if (is_null($teacherId)) {
1134            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
1135        }
1136
1137        if (isset($this->request->query['emergency']) && !$this->isStudySapuriTosUser) {
1138            return $this->redirect(myTools::getUrl() . '/waiting');
1139        }
1140
1141        //set mobile view
1142        if (myTools::defaultAction($this) || (isset($_GET['classViewTeacher']) && $_GET['classViewTeacher'] == 1)) {
1143            return $this->spDetail($teacherId);
1144        }
1145        $counselorParams = array(
1146            'type' => 'count',
1147            'args' => array(
1148                'conditions' => array(
1149                    'id' => $teacherId,
1150                    'counseling_flg' => 1
1151                ),
1152                'recursive' => -1
1153            )
1154        );
1155
1156        // - NC-3802: redirect to mypage if counselor teacher
1157        if ($this->Teacher->getTeachers($counselorParams)) {
1158            return $this->redirect('/mypage');
1159        }
1160
1161        $customer_support_flg = $this->TeacherDetail->isCustomerSupportTeacher($teacherId);
1162        //NJ-36255 - redirect to  customer support page if customer support teacher
1163        if($customer_support_flg){
1164            return $this->redirect('/customersupport_detail');
1165        }
1166        
1167        //NJ-65055: params for checking teacher is hidden
1168        $isTeacherHiddenParams = array(
1169            'user_id' => $this->Auth->user('id'),
1170            'teacher_id' => $teacherId
1171        );
1172
1173        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
1174            return $this->redirect('/waiting');
1175        }
1176
1177        // - NC-7031: redirect avatar
1178        $avatarData = $this->isAvatar($teacherId);
1179        if ($avatarData) {
1180            $getAId = $avatarData;
1181            return $this->redirect('/avatar_detail/'.$getAId);
1182        }
1183
1184        //redirect to proper profile
1185        $this->checkProperProfile($teacherId);
1186
1187        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
1188        $queryCondition = array(
1189            'fields' => array(
1190                    'TeacherRankCoin.coins',
1191                    'TeacherRankCoin.reserve_coin_settings_flg',
1192                    'LessonOnair.id',
1193                    'LessonOnair.teacher_id',
1194                    'LessonOnair.user_id',
1195                    'TeacherRankCoin.limited_plan_reservation'
1196                ),
1197            'joins' => array(
1198                array(
1199                    'type' => 'LEFT',
1200                    'table' => 'teacher_rank_coins',
1201                    'alias' => 'TeacherRankCoin',
1202                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
1203                )
1204            ),
1205            'conditions' => array(
1206                array('Teacher.id' => $teacherId)
1207            ),
1208            'show' => 'first'
1209        );
1210
1211        $commonTeacherStatusParams = array(
1212            'page_display' => 'listTeacher',
1213            'query_conditions' => $queryCondition
1214        );
1215        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
1216
1217        if (!$data) {
1218            return $this->redirect('/waiting/');
1219        }
1220
1221        if (in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
1222            return $this->redirect('/mypage');
1223        }
1224        // NJ-51 : Set delay for student lesson priority group
1225        $studentDelayInSeconds = 0;
1226        $standbyStatus = false;
1227        $remainingSeconds = 0;
1228        $chatHash = $this->request->query('chatHash') ?? null;
1229
1230        if( isset($data['LessonOnair']) && $data['LessonOnair'] ) {
1231            $loAir = $data['LessonOnair'];
1232            if( (isset($loAir['status']) && $loAir['status'] == 1) ) {
1233                $standbyStatus = true;
1234            }
1235        }
1236
1237        if( isset($data['TeacherStatus']) && $data['TeacherStatus'] && $data['TeacherStatus']['teacher_status'] == 2 ) {
1238            $tstatus = $data['TeacherStatus'];
1239            if( isset($tstatus['created']) && $tstatus['created'] ) {
1240                if( isset($data[0]['teacher_status_standby_duration']) && $data[0]['teacher_status_standby_duration'] ) {
1241                    if( (int)$data[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
1242                        $remainingSeconds = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$data[0]['teacher_status_standby_duration'];
1243                    }
1244                }
1245                $studentDelayInSeconds = (int) $remainingSeconds * 1000;
1246            }
1247        }
1248
1249        //- check lesson type
1250        $liveLessonFlg = isset($data['LessonOnair']['live_lesson_flg']) ? $data['LessonOnair']['live_lesson_flg'] : 0;
1251
1252        //-get userid
1253        $userId = isset($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : $this->Auth->user('id');
1254
1255        $ownReservationFlg = 0;
1256        if ( $userId ) {
1257            $teacherStatusColor = '';
1258            $teacherObj = new TeacherTable($data['Teacher']);
1259            $tsObj = new TeacherStatusTable($data['TeacherStatus']);
1260
1261            // get reservation
1262            $nextReservation = LessonScheduleTable::getReservation(array(
1263                'LessonSchedule.teacher_id' => $teacherObj->id,
1264                'LessonSchedule.user_id' => $userId
1265            ));
1266        
1267
1268            //-- if user cannot use live lesson -> force to disabled live lesson flag
1269            if ( isset($data['LessonOnair']['live_lesson_flg']) && empty($allowLiveLesson) ) {
1270                $data['LessonOnair']['live_lesson_flg'] = 0;
1271            }
1272
1273            $loStatusParams = array(
1274                'LessonOnair' => $data['LessonOnair'],
1275                'Teacher' => $data['Teacher'],
1276                'TeacherStatus' => $tsObj,
1277                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
1278                'userId' => $userId
1279            );
1280            $teacherStatus = LessonOnairTable::teacherStatusColor($loStatusParams);
1281            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatus);
1282            if( $teacherStatus == '5' ) {
1283                $ownReservationFlg = 1;
1284            }
1285
1286            // - user callan unli option flg
1287            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
1288
1289            // - user native unli option flg
1290            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
1291
1292            $can_use_callan_option = 0;
1293            if($callan_option || $native_option) {
1294                $can_use_callan_option = 1;
1295            }
1296
1297            $this->set('can_use_callan_option', $can_use_callan_option);
1298
1299            // - teacher callan unli option flg
1300            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
1301            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
1302            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
1303            
1304            // - check if has callan badge
1305            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
1306            $this->set('teacher_callan_badge', $teacher_callan_badge);
1307        }
1308
1309        //-default
1310        $liveStatus = 0;
1311
1312        //- fetch live waiting reservation
1313        $waitingReservationLive = [];
1314        if ($this->Auth->loggedIn() && $liveLessonFlg) {
1315            //- fetch user reservation
1316            $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($userId);
1317
1318            if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
1319                $liveStatus = 0;
1320            } else {
1321                //- if lesson started
1322                if (
1323                    !is_null($data['LessonOnair']['connect_id']) &&
1324                    !is_null($data['LessonOnair']['user_id'])
1325                ) {
1326                    if ($data['LessonOnair']['user_id'] == $userId) {
1327                        $liveStatus = 4;
1328                    } else {
1329                        //- check live status
1330                        $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
1331                            'user_id' => $userId,
1332                            'chat_hash' => $data['LessonOnair']['chat_hash']
1333                        ]);
1334
1335                        //-- override status to watch
1336                        if ($liveStatus == 1) {
1337                            $liveStatus = 2; //view live
1338                        }
1339                    }
1340                } else {
1341                    $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
1342                        'teacher_id' => $teacherId
1343                    ]);
1344
1345                    //-has reservation
1346                    if ($waitingReservationLive) {
1347                        if ($waitingReservationLive['LessonSchedule']['user_id'] == $userId) {
1348                            $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
1349                        } else {
1350                            $liveStatus = 1; //live will start
1351                        }
1352                    }
1353                }
1354            }
1355        }        
1356
1357        //redirect if withdrawn teacher
1358        if ($data['Teacher']['status'] <> 1 || $data['Teacher']['inactive_flg'] == 1) {
1359            if ($this->Auth->loggedIn()) {
1360                return $this->redirect(myTools::geturl() . '/mypage');
1361            } else {
1362                return $this->redirect(myTools::geturl() . '/waiting');
1363            }
1364        }
1365
1366        if (isset($data['LessonOnair'])) {
1367            $tmp = (object) $data['LessonOnair'];
1368            if (!$tmp->id) {
1369                $data['LessonOnair'] = null;
1370            }
1371        }
1372
1373        // get teacher information
1374        $teacher = new TeacherTable($data['Teacher']);
1375        $country = new TeacherTable($data['CountryCode']);
1376        $timezone = new TimezoneTable($data['Timezone']);
1377        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
1378
1379        $timeDiff = 0;
1380        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
1381            $timeDiffData = $this->Timezone->computeTimeDiff(array(
1382                'continent_id' => $timezone->continent_id,
1383                'city' => $timezone->city_eng
1384            ));
1385
1386            //
1387            if ($timeDiffData['success']) {
1388                $timeDiff = $timeDiffData['timeDiff'];
1389            }
1390        }
1391
1392        $onair = $data['LessonOnair'];
1393        $onairDataArr = isset($data['LessonOnair']) && $data['LessonOnair'] ? $data['LessonOnair'] : array();
1394
1395        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
1396
1397        $fieldArr = array(
1398            'TextbookCategory.name',
1399            'TextbookCategory.id',
1400            'TextbookCategory.type_id',
1401            'TeacherBadge.textbook_category_id',
1402            'TeacherBadge.badge_flg',
1403            'TextbookCategory.type_id',
1404            'TextbookCategory.image_big_url'
1405        );
1406        $joinArr = array(
1407            array(
1408                'table' => 'teacher_badges',
1409                'alias' => 'TeacherBadge',
1410                'type' => 'LEFT',
1411                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $teacherId)
1412            )
1413        );
1414
1415        // if the user's language is zh-tw, display chinese textbook badge name
1416        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
1417            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
1418            if($langId){
1419                $joinArr[] = array(
1420                    'type' => 'LEFT',
1421                    'table' => 'global_textbook_categories',
1422                    'alias' => 'GlobalTextbookCategory',
1423                    'conditions' => array(
1424                        'GlobalTextbookCategory.language_id' => $langId,
1425                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
1426                    )
1427                );
1428                $this->TextbookCategory->virtualFields = array(
1429                    'gl_name' => 'GlobalTextbookCategory.gl_name'
1430                );
1431                $fieldArr[] = 'gl_name';
1432            }
1433        }
1434
1435        $conArr = array(
1436            'TextbookCategory.status' => 1,
1437            'TextbookCategory.type_id' => 2
1438        );
1439
1440        # get studydapuri textbooks
1441        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
1442        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
1443            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
1444            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
1445        } elseif ($this->isStudySapuriTosUser) {
1446            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
1447        } else {
1448            $exCat = Configure::read('all_sapuri_textbook_category_types');
1449            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
1450        }
1451
1452        //NJ-24096: get last reservation textbook type
1453        $reservationTextbookConnectId = "";
1454        if ($userId) {
1455            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true : false;
1456            $lastReservationData = LessonScheduleTable::getLastReservation($this->Auth->user('id'), $sapuriFlg);
1457
1458            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
1459                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
1460            } else {
1461                $this->User->openDBReplica();
1462                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
1463                $this->User->closeDBReplica();
1464                if (empty($checkUserFirstFlg)) {
1465                    $defaultParams = array(
1466                        'user_id' => $userId,
1467                        'lang' => $userData->native_language2 ?? $this->localizeDir,
1468                    );
1469                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
1470                    if ($defaultReservation) {
1471                        $reservationTextbookConnectId = $defaultReservation;
1472                    }
1473                }
1474            }
1475        }
1476        $this->set(compact('reservationTextbookConnectId'));
1477
1478        // NJ-5836
1479        $displayRestrictionParams = array(
1480            'lang' => $this->localizeDir
1481        );
1482
1483        // get display restriction setting
1484        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
1485
1486        // NJ-5836 add condition for display restriction
1487        if(isset($displayRestriction['field']) && $displayRestriction['field']){
1488            // set condition for display restriction
1489            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
1490        }
1491
1492        //get series and badge
1493        $series = $this->TextbookCategory->find('all', array(
1494            'fields' => $fieldArr,
1495            'conditions' => $conArr,
1496            'joins' => $joinArr,
1497            'order' => array(
1498                'TextbookCategory.sort' => 'ASC'
1499            )
1500        ));
1501
1502        $this->set('series', $series);
1503        myTools::initializeApiTunnel(array('TeachersDetailController'));
1504        $teachersDetail = new TeachersDetailController();
1505
1506        $teacherTbRatings = array();
1507        
1508        if (isset($series) && is_array($series) && count($series) > 0) {
1509            foreach($series as $books){            
1510                $categoryId = $books['TextbookCategory']['id'];
1511                $params = array(
1512                    'teacher_id' =>  (int) $teacherId,
1513                    'textbook_category_id' => (int) $categoryId,
1514                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
1515                );
1516                $teachersDetail->params = $params;        
1517                $decodeResp = json_decode($teachersDetail->teacherTextbookRating());
1518                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
1519            }
1520        }
1521
1522        $this->set('teacherTbRatings', $teacherTbRatings);
1523
1524        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
1525
1526        $this->set('historyMonth',$historyMonth);
1527        $this->set('historyYear',$historyYear);
1528
1529        //teacher_status if login or break
1530        $teacherStatus1 = $this->TeacherStatus->find('first', array(
1531            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
1532            'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
1533        ));
1534
1535        //lesson onair
1536        if (!empty($onair)) {
1537            $oOnair = new LessonOnairTable($onair);
1538        } else {
1539
1540            if (!empty($teacherStatus1)) {
1541                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
1542            } else {
1543                $oOnair = 0;
1544            }
1545        }
1546
1547        // NJ-17264
1548        $teacherTitleThreshold = 0;
1549        if(isset($data['TitleThresholdTeacher']['title_type'])){
1550            $teacherTitleThreshold = $data['TitleThresholdTeacher']['title_type'];
1551        }
1552
1553        // inital teacher status
1554        $initialTeacherStatus = isset($teacherStatus1['TeacherStatus']) && $teacherStatus1['TeacherStatus']['status'] ? $teacherStatus1['TeacherStatus']['status'] : 0;
1555
1556        //favorite
1557        $where = array(
1558            'UsersFavorite.user_id'     => $this->Auth->user('id'),
1559            'UsersFavorite.teacher_id'     => $teacherId,
1560        );
1561        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
1562
1563        // NC-5897 : check if teacher was hide by user.
1564        $where = array(
1565            'user_id' => $this->Auth->user('id'),
1566            'teacher_id' => $teacherId,
1567        );
1568        $isHide = $this->BlockList->isTeacherHide($where);
1569        $this->User->recursive = -1;
1570        $data = $this->User->findById($userId);
1571        $user = isset($data['User'])?$data['User']: null;
1572        $unsupportedBrowser = false;
1573        $browser =  $this->request->header('User-Agent');
1574
1575        if (preg_match('/(Edg|Edge)/i',$browser) ) {
1576            $unsupportedBrowser = false;
1577        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
1578            $unsupportedBrowser = true;
1579        }
1580        $canReport = true;
1581        if ($user) {
1582            $userData = new UserTable($data['User']);
1583            $userMembership = $userData->getUserMembership();
1584            $this->set('user_lang', $userData->native_language2);
1585            // if weekly plan user
1586            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
1587            $corporateUser = isset($corporateType) ? $corporateType : '';
1588
1589            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
1590            $canReport = $userData->getMembershipTypeIndex();
1591            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
1592        }
1593        $this->set('unsupportedBrowser', $unsupportedBrowser);
1594        // NC-6615 check if user can report the teacher
1595        $this->set('canReport', $canReport);
1596
1597        $hideLimitedPlanReservation = false;
1598        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
1599            $hideLimitedPlanReservation = true;
1600        }
1601
1602        $firstTimeLoggedIn = false;
1603        if (empty($user['last_login_time'])) {
1604            $firstTimeLoggedIn = true;
1605        }
1606
1607        $paidParent = false;
1608
1609        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
1610            'conditions' => array(
1611                'user_id' => $this->Auth->user('id'),
1612                'status' => 0
1613            )
1614        ));
1615
1616        $countryCodes = $this->CountryCode->find('all',array(
1617            'fields' => array(
1618                'code',
1619                'country_name'
1620            ),
1621            'order' => 'country_name ASC'
1622        ));
1623        $this->set('countryCodes',$countryCodes);
1624
1625        $userCountry['CountryCode']['country_name'] = '';
1626        $userCountry['CountryCode']['code'] = '';
1627        if(!empty($data['User']['country_code'])){
1628            $userCountry = $this->CountryCode->find('first',array(
1629                'conditions' => array(
1630                    'code' => $data['User']['country_code']),
1631                'fields' => array(
1632                    'code',
1633                    'country_name')
1634            ));
1635            if(empty($userCountry)){
1636                $userCountry['CountryCode']['code'] = '';
1637            }
1638        }
1639        $this->set('countryCodes',$countryCodes);
1640
1641        //check if user is child by checking its parent id not empty
1642        if (isset($data['User']['parent_id'])) {
1643            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
1644        }
1645        #$lesson_count=0;
1646        // 管理者権限会員は無制限でレッスン出来る
1647        if (isset($user['admin_flg']) && $user['admin_flg']=='1') {
1648            $user['charge_flg'] = 1;
1649            $lesson_count=0;
1650            $lesson_count_today = 0;
1651        }
1652
1653        if (empty($user['enquate6'])) {
1654            $user['enquate6'] = '1';
1655        }
1656
1657        if (empty($user['enquate7'])) {
1658            $user['enquate7'] = '1';
1659        }
1660
1661        // if tos user
1662        if (isset($this->sharedUserData['UsersExtend']['id'])) {
1663            $user['tos_user'] = true;
1664        }
1665
1666        //number of stusap lesson
1667        $stusapLessonCount = (int)$teacher->stusap_lesson_count + (int)$teacher->stasapu_tos_lesson_count;
1668        //number of lesson
1669        $lessonCount = (int)$teacher->lesson_count;
1670
1671        // - prepare head text
1672        $headTextWD = $pageTitleWD = $teacher->name;
1673        $metaDescWD = "";
1674        if ($this->localizeDir == Configure::read('default.user_language')) {
1675            $headTextWD .= '('.$teacher->jp_name.')';
1676            $pageTitleWD .=  '('.$teacher->jp_name.')';
1677            //$metaDescWD .= '('.$teacher->jp_name.')';
1678        }
1679
1680        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
1681            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').': '.$lessonCount . ' ' . lcfirst(($lessonCount <= 1 ?  __dx('waiting', 'singular', '回') :  __d('waiting', '回'))); 
1682        } else { // if the language is not Custom language format
1683            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').':'.$lessonCount. __d('waiting','回');
1684        }
1685        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
1686        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
1687
1688        //prepare meta image 
1689        $_teacherImgUrl = $teacher->getImageUrl();
1690
1691        //check if teacher has no image 
1692        if (empty($teacher->image_url) || !$teacher->image_url) {
1693            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
1694            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
1695        }
1696
1697
1698        // - set page meta information
1699        $this->set('headtext', $headTextWD);
1700        $this->set('title_for_layout', $pageTitleWD);
1701        // $this->set('meta_description', $metaDescWD);
1702        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
1703        $this->set('counselingFlg',$teacher->counseling_flg);
1704        $this->set('meta_teacher_img',$_teacherImgUrl);
1705
1706        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
1707        $options['language_id'] = $reviewLanguage[0] ?? null;
1708        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
1709
1710        $userTable = new UserTable($this->Auth->user());
1711        $sapuriPlan = $userTable->isStudySapuri();
1712        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
1713        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
1714            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
1715        } else {
1716            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
1717        }
1718        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId , $options);
1719        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
1720
1721        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
1722        $get_weekly_rating['TeacherWeeklyRating']['averageRate'] ??= '';
1723        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
1724            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) {
1725                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = number_format($get_weekly_rating['TeacherWeeklyRating']['averageRate'], 2, ',', '');
1726            } else {
1727                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
1728            }
1729        }
1730
1731        /* -- NC-5293 start -- */
1732        $this->loadModel('Translation');
1733        $translationCategories = Configure::read('translation_categories');
1734        $translateParams = array(
1735            'languageCode' => $this->lang_iso,
1736            'categoryId' => $translationCategories['teacher_message'],
1737            'messageId' => $teacher->id,
1738            'text' => $teacher->message
1739        );
1740
1741        $translatedMessageParams = $translateParams;
1742        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
1743        $translateParams['text'] = $teacher->self_introduction_third_pp;
1744        $translatedSelfIntroductionThirdPpParams = $translateParams;
1745        /* -- NC-5293 end -- */
1746
1747        // Translate and save translated data
1748        $globalTranslate = TeacherTable::translate(array(
1749            'id' => $teacherId,
1750            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
1751            'controller' => static::class
1752        ));
1753        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
1754        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
1755        $this->set('message', $translatedMessageTranslation);
1756        $this->set('intro', $translatedThirdppTranslation);
1757
1758        //find the selfintro 
1759        $TeacherTable = new TeacherTable($teacher);
1760        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
1761        $_userSelfIntro = strip_tags($_userSelfIntro); 
1762
1763        //set the new meta description
1764        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
1765        $this->set('meta_description', $metaDescWD);
1766
1767        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($data['User']['payment_plan_id']);
1768        $canCoinPurchase = true;
1769        if (isset($data['User']['corporate_id']) && isset($corporateType)) {
1770            if (in_array($corporateType, array(Configure::read('corporate_type.standard'), Configure::read('corporate_type.premium')))) {
1771                $canCoinPurchase = true;
1772            } else {
1773                $canCoinPurchase = false;
1774            }
1775        }
1776
1777        //
1778        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
1779
1780        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
1781        $coinParams =  array(
1782            'current_rank_id' => $teacherCurrentRankId,
1783            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
1784            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
1785            'student_native_option' => $userData->native_option,
1786            'home_flg' => $teacher->home_flg,
1787            'counseling_flg' => $teacher->counseling_flg,
1788            'avatar_parent_flg' => $teacher->avatar_parent_flg,
1789            'avatar_flg' => $teacher->avatar_flg,
1790            'native_speaker_flg' => $teacher->native_speaker_flg
1791        );
1792
1793        // get teacher coin settings
1794        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
1795
1796        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
1797        $displayNativeOptionAmountFlg = false;
1798        if($teacherCoinData){
1799            // set teacher reservation coin
1800            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
1801            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
1802            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
1803            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
1804        }
1805        $teacherCoin = $teacherCoin ?? 0;
1806        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
1807
1808        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
1809
1810        $sapuriCoin = 0;
1811        if ($this->isStudySapuriUser) {
1812            $teacherParams = array(
1813                'teacher_id' => $teacher->id,
1814                'current_rank_id' => $teacherCurrentRankId
1815            );
1816            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
1817        }
1818
1819        $ongoingLessonWithOtherStudentButtonDelay = 0;
1820        if($onairDataArr){
1821            if( 
1822                (isset($onairDataArr['user_id']) && $onairDataArr['user_id'] != $userId) && 
1823                (isset($onairDataArr['status']) && $onairDataArr['status'] == '3') && 
1824                (int)$this->studentLessonPriorityTimeDelayInSeconds > 0
1825            ) {
1826                $ongoingLessonWithOtherStudentButtonDelay = 1;
1827            }    
1828        }
1829    
1830        // set lesson review modal on/off
1831        $this->set('lesson_review_flg', $data['User']['lesson_review_flg']);
1832        $where = array(
1833            'UsersFavorite.teacher_id' => $teacherId,
1834        );
1835
1836        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
1837        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $isFav? [$teacher->id]: []]);
1838        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
1839            'favIds' => $isFav? [$teacher->id]: [],
1840            'favIdsTeacherCategory' => $teacherFavColor
1841        ]);
1842        
1843        // NJ-3696
1844        $this->LessonOnairsLog->openDBReplica();
1845        $textbook = $this->LessonOnairsLog->find('first', array(
1846            'fields' => array(
1847                'TextbookCategories.id',
1848                'TextbookCategories.textbook_category_type'
1849            ),
1850            'joins' => [
1851            [
1852                'table' => 'textbook_connects',
1853                'alias' => 'TextbookConnects',
1854                'type' => 'left',
1855                'conditions' => ["TextbookConnects.id = LessonOnairsLog.connect_id"]
1856            ],
1857            [
1858                'table' => 'textbook_categories',
1859                'alias' => 'TextbookCategories',
1860                'type' => 'left',
1861                'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1862            ]
1863        ],
1864            'conditions' => array('LessonOnairsLog.chat_hash' => $chatHash),
1865            'recursive' => -1
1866        ));
1867        $this->LessonOnairsLog->closeDBReplica();
1868    
1869        if(!$textbook){
1870            $this->LessonOnair->openDBReplica();
1871            $textbook = $this->LessonOnair->find('first', array(
1872                'fields' => array(
1873                    'TextbookCategories.id',
1874                    'TextbookCategories.textbook_category_type'
1875                ),
1876                'joins' => [
1877                    [
1878                        'table' => 'textbook_connects',
1879                        'alias' => 'TextbookConnects',
1880                        'type' => 'left',
1881                        'conditions' => ["TextbookConnects.id = LessonOnair.connect_id"]
1882                    ],
1883                    [
1884                        'table' => 'textbook_categories',
1885                        'alias' => 'TextbookCategories',
1886                        'type' => 'left',
1887                        'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1888                    ]
1889                ],
1890                'conditions' => array('LessonOnair.chat_hash' => $chatHash),
1891                'recursive' => -1
1892            ));
1893            $this->LessonOnair->closeDBReplica();
1894        }
1895
1896        //NJ-20590
1897        $teacher->image_url = myTools::checkAndReturnPresignedUrl($teacher->image_url);
1898
1899
1900        $hash = $this->request->query['chatHash'] ?? null;
1901        if(!empty($hash)){
1902            if (!class_exists('myMemcached')) {
1903                App::uses('myMemcached', 'Lib');
1904            }
1905            $memcached = new myMemcached();
1906            $appreciationDoneCache = $memcached->get("appreciation_done_".$hash);
1907            $this->set("isAppreciationDone", $appreciationDoneCache == 1 ? 1 : 0);
1908        }
1909
1910        // NJ-NJ-62396
1911        $isCallanTextbook = (!empty($textbook['TextbookCategories']['textbook_category_type']) && in_array($textbook['TextbookCategories']['textbook_category_type'], Configure::read('callan_textbook_type'))) ? 1 : 0;
1912
1913
1914        // NJ-3696
1915        // set view vars
1916        $setData = array(
1917            'textbookCategory' => $textbook['TextbookCategories'] ?? [],
1918            'teacher' => $teacher,
1919            'onair' => $oOnair,
1920            'isFav' => $isFav,
1921            'isHide' => $isHide,
1922            'ongoingLessonWithOtherStudentButtonDelay' => $ongoingLessonWithOtherStudentButtonDelay,
1923            'initialTeacherStatus' => $initialTeacherStatus,
1924            'teacherFavsColors' => $teacherFavsColors,
1925            'favoriteCount' => $favoriteCount,
1926            'tId' => $teacher->id,
1927            'user' => $user,
1928            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
1929            'userMembership' => isset($userMembership)?$userMembership:'',
1930            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
1931            'enquate6_options' => UserTable::getEnquate6(),
1932            'enquate7_options' => UserTable::getEnquate7(),
1933            'stusapLessonCount' => $stusapLessonCount,
1934            'lessonCount' => $lessonCount,
1935            'commentCount' => $commentCount,
1936            'userId' => $userId,
1937            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
1938            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
1939            'callanCoin' => (int)$callanCoin,
1940            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
1941            'isCallanTextbook' => $isCallanTextbook,
1942            'UserData' => $data,
1943            'userCountry' => $userCountry,
1944            'velifyCount' => $velifyCount,
1945            'firstTimeLoggedIn' => $firstTimeLoggedIn,
1946            'isLoggedIn' => $this->Auth->loggedIn(),
1947            'country' => $country,
1948            'timeDiff' => $timeDiff,
1949            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
1950            'translatedMessageParams' => $translatedMessageParams,
1951            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
1952            'translationModel' => $this->Translation,
1953            'weekly_ratings' => isset($get_weekly_rating['TeacherWeeklyRating']) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
1954            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
1955            'canCoinPurchase' => $canCoinPurchase,
1956            'liveStatus' => $liveStatus,
1957            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
1958            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
1959            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
1960            'sapuriCoin' => $sapuriCoin,
1961            'isEmergencyPage' => !empty($this->request->query['emergency']) ? true : false,
1962            'teacherTitleThreshold' => $teacherTitleThreshold,
1963        );
1964
1965        $this->set($setData);
1966        if ($userId) {
1967            $points = $this->UsersPoint->find('first', array(
1968                'fields' => array('point'),
1969                    'conditions' => array(
1970                        'user_id' => $userId
1971                    )
1972                )
1973            );
1974
1975            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
1976            $reservePoint = Configure::read("reserve_point");
1977
1978            if (intval($reservePoint) < 1) $reservePoint = 0;
1979            //set promo discount for reservation
1980            // set paramater to 2 for reservation promo
1981            $bonus = CoinSetTable::getCoinSet(2);
1982            //check if the promo is valid today
1983            if ($bonus) {
1984                $reservePoint = $bonus;
1985            }
1986        } else {
1987            $points = 0;
1988        }
1989
1990        # get user timezone
1991        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
1992        $user_timezone_data = $this->Timezone->find('first',
1993            array(
1994                'fields' => array(
1995                    'Timezone.city_eng',
1996                    'Timezone.utc_offset',
1997                    'Timezone.country_code_id'
1998                ),
1999                'conditions' => array(
2000                    'Timezone.id' => $user_timezone_id
2001                ),
2002                'recursive' => -1
2003            )
2004        );
2005
2006        // - NJ-3653 get country
2007        $countryTimezone = null;
2008        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
2009            // - Get all country Code
2010            $countryOptions = $this->Timezone->countryOptions();
2011
2012            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
2013            $countryName = $countryOptions[$countryCodeId]['country_name'];
2014
2015            if (isset($countryName) && $countryName) {
2016                $countryTimezone = $countryName;
2017            }
2018        }
2019
2020        $this->set('countryTimezone', $countryTimezone);
2021        $this->set('userTimezoneData', $user_timezone_data);
2022
2023        #user time
2024        $datetime = date('Y-m-d H:i:s');
2025        $localTime = $this->displayTime;
2026        // NJ-29496
2027        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
2028            $formattedDate = date('d/m/Y G:i', $localTime);
2029        } else {
2030            $formattedDate = date('Y/m/d G:i', $localTime);
2031        }
2032        $this->set('userCurrentTime', $formattedDate);
2033
2034        $this->set('points', $points);
2035        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
2036
2037        $countrids_no = Configure::read('sms_send.countrids_no');
2038        $this->set('countrids_no', $countrids_no);
2039
2040        $deviceNotSupported = false;
2041        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
2042        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
2043            $deviceNotSupported = true;
2044        }
2045        $this->set('deviceNotSupported', $deviceNotSupported);
2046
2047        $userLang = !empty($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
2048        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
2049        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
2050        $residenceData = $this->getResidenceData($getCRData);
2051        $this->set('residenceData',$residenceData);
2052        $this->set('residenceFlg',$residenceData['countryFlag']);
2053        $this->set('deviceNotSupported', $deviceNotSupported);
2054        $this->set('statusCheck', array(1, 4));
2055
2056        $this->set('login', $this->Auth->loggedIn());
2057        $preset = array();
2058        if($this->Auth->User('id')) {
2059            //get preset textbook -> last viewed -> default textbook category first lesson
2060            $presetParams = array("user_id" => $this->Auth->User('id'));
2061
2062            //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
2063            $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
2064            //add additional parameters
2065            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
2066                $presetParams["lang"] = $this->localizeDir;
2067            }
2068
2069            #NC-9916
2070            if($data['User']) {
2071                $presetParams['native_language2'] = $userData->native_language2;
2072                $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
2073            }
2074
2075            $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
2076            if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
2077                # for preset
2078                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
2079                $presetParams['last_opened_date'] = $preset_data['preset_last_viewed_date'];
2080
2081            } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
2082                # use last viewed textbook if no preset data.
2083                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
2084                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
2085
2086            }
2087
2088            // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
2089            $presetParams['is_pc_flg'] = 1;
2090
2091            # fetch preset
2092            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2093            if(!$preset) {
2094                unset($presetParams['connect_id']);
2095                unset($presetParams['last_opened_date']);
2096                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2097            }
2098        }
2099
2100        //set variable preset textbook to be displayed
2101        $this->set('preset', $preset);
2102
2103        // NJ-8416: check for textbook live_lesson_flg is ON
2104        $textbookCategory = isset($preset['textbook_info']['TextbookCategory']) ? $preset['textbook_info']['TextbookCategory'] : array();
2105        $presetIsLiveTextbook = (isset($textbookCategory['live_lesson_flg']) && $textbookCategory['live_lesson_flg']) ? true : false;
2106        $this->set('presetIsLiveTextbook', $presetIsLiveTextbook);
2107
2108        // apology list (cancellation of reservation)
2109         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
2110
2111         // -- NJ-18780: is normal lite plan user 
2112        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
2113        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
2114
2115        $this->set('apologyList', $apologyList);
2116        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
2117            'userId' => $this->Auth->user('id'),
2118            'teacherId' => $teacherId,
2119            'timeDiff' => $this->timeDiff,
2120            'isNormalLitePlanUser' => $isNormalLitePlanUser
2121        ));
2122        $this->set('disabledSchedule', json_encode($disabledSchedule));
2123        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
2124        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
2125        $this->set('isNormalLitePlanUser',$isNormalLitePlanUser);
2126
2127        //NC-7603 get keep memo
2128        $getKeepMemo = $this->UsersMemo->find('first', array(
2129            'fields' => array(
2130                'id',
2131                'memo'
2132            ),
2133            'conditions' => array(
2134                'user_id' => $this->Auth->user('id'),
2135                'teacher_id' => $teacherId,
2136                'type' => 0
2137            ),
2138            'order' => array('created DESC'),
2139        ));
2140
2141        $this->set('keep_memo', $getKeepMemo);
2142
2143        // NC-8020
2144        $this->set('textbookConnectId', $preset['textbook_connect_id']);
2145        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
2146
2147        // - NJ-6390 add highLightFlag
2148        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
2149
2150        // NJ-42
2151        $liveCoin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(['current_rank_id' => $teacher->current_rank_id]);
2152        $this->set('liveCoin', number_format((float)$liveCoin));
2153
2154        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
2155        //NC-7984 start
2156        $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir);
2157        if(!empty($lesson_history_data)) {
2158            $this->set('lessonHistory', $lesson_history_data['lessonHistory']);
2159            $this->set('textbookNamesCachedArr', $lesson_history_data['textbookNamesCachedArr']);
2160        }
2161        //NC-7984 end
2162        
2163        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
2164        $this->set('showRating', $showRating);
2165
2166        //NJ-20069 teacher
2167        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
2168        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null);
2169        $lessonHistoryCount  = count($lessonHistory['lessonHistory']);
2170        $latestUserLesson = isset($lessonHistory['lessonHistory'][0]['LessonOnairsLog']) ? $lessonHistory['lessonHistory'][0]['LessonOnairsLog'] : null;
2171        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
2172        
2173        // - if has translated Category name
2174        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
2175            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
2176        }
2177        
2178        $formattedLatestLessonData = "";
2179        if(!empty($latestUserLesson))
2180        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
2181        
2182        $teacherLastLogin = $teacher->last_login_time;
2183        $formattedTeacherLastLogin = "";
2184        if(!empty($teacherLastLogin)) {
2185            if ($this->localizeDir == 'pt-br') {
2186                $daysOfWeekPtBr = [
2187                    'Sun' => __dx('account', 'week', '日'), // Dom
2188                    'Mon' => __dx('account', 'week', '月'), // Seg
2189                    'Tue' => __dx('account', 'week', '火'), // Ter
2190                    'Wed' => __dx('account', 'week', '水'), // Qua
2191                    'Thu' => __dx('account', 'week', '木'), // Qui
2192                    'Fri' => __dx('register', 'week', '金'), // Sex
2193                    'Sat' => __dx('account', 'week', '土')  // Sab
2194                ];
2195                $dayOfWeekPtBr = $daysOfWeekPtBr[date('D', strtotime($teacherLastLogin))];
2196        $formattedTeacherLastLogin = date('d/m/Y', strtotime($teacherLastLogin)) . " ({$dayOfWeekPtBr}";
2197            } else {
2198                $formattedTeacherLastLogin = date('Y-m-d',strtotime($teacherLastLogin)). " (" . date('D',strtotime($teacherLastLogin)) . ") ";
2199            }
2200        }
2201
2202        $this->set('lessonHistoryCount', $lessonHistoryCount);
2203        $this->set('latestUserLesson', isset($lessonHistory['lessonHistory'][0]) ? $lessonHistory['lessonHistory'][0] : null);
2204        $this->set('teacherRates', $reserveAndCancel);
2205        $this->set('teacherIdCheck', $teacherId);
2206        $this->set('latestLessonData', $formattedLatestLessonData);
2207        $this->set('teacherLastLogin', $formattedTeacherLastLogin);
2208        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
2209
2210        $this->TeacherFeature->openDBReplica();
2211        $teacherFeatures = $this->TeacherFeature->find('first', array(
2212            'conditions' =>  array(
2213                'TeacherFeature.teacher_id' => $teacherId
2214            )
2215        ));
2216        $this->TeacherFeature->closeDBReplica();
2217        
2218        # NJ-19429: fetch campaign
2219        $studentID = $this->Auth->user('id');
2220        $inCampaignDetails = $this->CampaignInstructor->getValidateUserCampaign($teacherId, $studentID);
2221
2222        //NJ-47494 - add 8 day checker for campaign
2223        $now = date('Y-m-d');
2224        $dayTimer = date('Y-m-d', strtotime('+7 days'));
2225        
2226        $inCampaignStartDate = isset($inCampaignDetails['CampaignInstructor']['start_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['start_date'])) : null;
2227        $inCampaignEndDate = isset($inCampaignDetails['CampaignInstructor']['end_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['end_date'])) : null;
2228        $validCampaignDate = !($dayTimer < $inCampaignStartDate || $now > $inCampaignEndDate);
2229
2230        if ($inCampaignDetails && $validCampaignDate == 1){
2231            $campaign = $inCampaignDetails['CampaignInstructor'];
2232
2233            $campaignTag = '';
2234            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
2235                $campaignTag .= $campaign['discount'] == 100 ? '100% OFF ' : '50% OFF ';
2236                $campaignTag .= '(' . __d('waiting',Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]) . ') ';    
2237
2238                // NJ-47838 GGPE FB10
2239                if((int) $campaign['classification'] == 4) {
2240                    $campaignTag = __d('waiting', Configure::read('campaign_instructor_tags')[$campaign['campaign_tag_id']]);
2241                }
2242            } else { // if the language is not Custom language format
2243                $campaignTag .= $campaign['discount'] == 100 ? '100%OFF ' : '50%OFF ';
2244                $campaignTag .= '('.Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]. ') ';
2245                $campaignTag .= Configure::read('campaign_instructor_type')[$campaign['classification']] . '講師';
2246            }
2247
2248            $teacherFeatures['CampaignTag'] = $campaignTag;
2249
2250            // NJ-47838
2251            $teacherFeatures['CampaignTagClassification'] = $campaign['classification'];
2252            // NJ-47838 : Set a flag if the campaign is classified as "Live"
2253            $teacherFeatures['IsCampaignLive'] = ($campaign['classification'] === 4);
2254
2255            // NJ-47838 : Ensure the campaign discount is set if the campaign is live and the teacher is registered for it
2256            if ($teacherFeatures['IsCampaignLive']) {
2257                $teacherFeatures['CampaignLiveDiscount'] = $campaign['discount'];
2258            }
2259        }
2260
2261        if(isset($campaign) && $campaign){
2262            $this->set('campaignDiscount', isset($campaign['discount']) ? $campaign['discount'] : null);
2263            $this->set('campaignTextbook', isset($campaign['textbook_type']) ? $campaign['textbook_type'] : null);
2264            $this->set('campaignDiscountClassification', isset($campaign['classification']) ? $campaign['classification'] : null);
2265        }
2266
2267        $this->set('teacherFeatures', $teacherFeatures);
2268        
2269        // NJ-3786 textbook teacher recommendation
2270        $curDate = date('Y-m-d');
2271        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
2272        $txtTeacherRecommendlimit = 10;
2273        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
2274        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
2275        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
2276
2277        if( $userId ) {
2278            // - NJ-8416: check for last lesson type
2279            $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
2280            $this->log('[NJ-8416 lastLessonType waitingDetail] -> ' . json_encode($lastLessonType), 'debug');
2281            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
2282                'user_id' => $userId,
2283                'limit' => 10, // waiting detail page
2284                'last_lesson_type' => $lastLessonType
2285            ) );
2286            $textbookCategoryId = $lastBookUsedData['category_id'];
2287            $textbookBadge = $lastBookUsedData['textbook_badge'];
2288            $this->log('[NJ-8416 textbookCategoryId waitingDetail] -> ' . json_encode($textbookCategoryId), 'debug');
2289            $paramsArr = array(
2290                'user_id' => $userId,
2291                'begin_date' => $beginDate,
2292                'end_date' => $endDate,
2293                'textbook_category' => $textbookCategoryId,
2294                'textbook_badge' => $textbookBadge,
2295                'limit' => $txtTeacherRecommendlimit,
2296                'user_data' => $userData,
2297                'exclude_teacher_id' => $teacherId
2298            );
2299
2300            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
2301            if( $teacherTextbookStatData ) {
2302                $dataList = $this->arrangeTeacherRecommendList( array( 
2303                        'user_id' => $userId,
2304                        'data' => $teacherTextbookStatData,
2305                        'category_id' => $textbookCategoryId,
2306                        'user_data' => $userData
2307                    ) 
2308                );
2309                $this->set('textbookTeacherData', $dataList);
2310            }
2311        }
2312
2313        $ownReservationTeacherData = $this->LessonSchedule->getWaitingToJoinReservationTeacherInfo( array( 'user_id' => $this->Auth->user('id'), 'limit_checker_flag' => 1 ) );
2314        $this->set( 'ownReservationTeacherId', $ownReservationTeacherData['teacher_id'] ); // live lesson work-around
2315        $this->set( 'lessonScheduleOwnReservationTeacher', isset($lessonScheduleOwnReservationTeacherData['teacher_id']) ? $lessonScheduleOwnReservationTeacherData['teacher_id'] : null ); // live lesson work-around
2316        $this->set( 'studentDelayInSeconds', (int)$studentDelayInSeconds );
2317        $this->set( 'remainingSeconds', (int)$remainingSeconds );
2318        $this->set( 'ownReservationFlg', $ownReservationFlg );
2319        $this->set( 'teacherStatusColor', $teacherStatusColor );
2320
2321        if ($this->request->query('chatHash')) {
2322            $chatHash = $this->request->query('chatHash');
2323
2324            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2325            $this->set('data',  $allData);
2326
2327            $friParams = array(
2328                'type' => 0,
2329                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
2330                'from' => 'user'
2331            );
2332
2333            $strengthItems = $this->FeatureRatingItem->getActiveItems($friParams);
2334
2335            // get active weakness feature rating items
2336            $friParams['type'] = 1;
2337            $weaknessItems = $this->FeatureRatingItem->getActiveItems($friParams);
2338
2339            $this->set('strengthItems', $strengthItems);
2340            $this->set('weaknessItems', $weaknessItems);
2341            
2342            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2343
2344            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
2345                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
2346
2347                if(!$allData) {
2348                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
2349                }
2350            }
2351
2352            $this->set('data',  $allData);
2353
2354            $live_lesson_viewer = 0;
2355            if((!empty($allData['LessonOnairsLog']) && $allData['LessonOnairsLog']['live_lesson_flg'] == 1 && $allData['LessonOnairsLog']['user_id'] != $userId)
2356                || (!empty($allData['LessonOnair']) && $allData['LessonOnair']['live_lesson_flg'] == 1 && $allData['LessonOnair']['user_id'] != $userId)
2357            ) { $live_lesson_viewer = 1; }
2358            
2359            // get last feature rating items
2360            if($live_lesson_viewer){
2361                $lastRatingItems = $this->ViewerFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2362            } else {
2363                $lastRatingItems = $this->UserFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2364            }
2365            
2366            $this->set('lastSelectedStrengthItems', isset($lastRatingItems['strengthItems']) ? $lastRatingItems['strengthItems'] : array());
2367            $this->set('lastSelectedWeaknessItems', isset($lastRatingItems['weaknessItems']) ? $lastRatingItems['weaknessItems'] : array());
2368
2369            $userValidForSSBEDT = false;
2370            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
2371                $userValidForSSBEDT = true;
2372            }
2373            $param = array(
2374                "user_id" => $userId,
2375                "select_method" => "first",
2376                "env_flag" => "all",
2377                'connect_id' => $allData['Connect']['id'],
2378                "user_locale" => $this->localizeDir,
2379                "userValidForSSBEDT" => $userValidForSSBEDT
2380            );
2381            //NJ-12326
2382            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
2383                $corporateParams = array('user_id' => $userId);
2384                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
2385                
2386                if ($corporateTextbookControlFlg == 1) {
2387                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
2388                    if (!empty($categoryData)) {
2389                        $param['include_kids_category'] = $allData['Connect']['category_id'];
2390                    }
2391                }
2392            }
2393            $textbookData = $this->Textbook->getTextbooks($param);
2394            $data = $textbookData['res_data'];
2395
2396            $isReservedLesson = 2;
2397            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
2398            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
2399            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
2400            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
2401            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
2402
2403            //NJ-3626 Optimize PC /lesson-finish page
2404            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
2405            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
2406                $lessonOnairLatestDataFlg = true;
2407                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
2408                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
2409            } else {
2410                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
2411                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
2412                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
2413                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
2414                }
2415            }
2416
2417            // - initialize empty variable
2418            $isLatestPresetTextbookMadeDuringLastLesson = [];
2419            $latestPresetTextbookParams = [];
2420
2421            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
2422            if ($lessonOnairLatestDataFlg) {
2423                $latestPresetTextbookParams = array (
2424                    'userId' => $userId,
2425                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2426                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
2427                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
2428                );
2429
2430            // - if has lesson onairs log
2431            } else if ($lessonOnairLogsLatestData) {
2432                $latestPresetTextbookParams = array (
2433                    'userId' => $userId,
2434                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2435                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
2436                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
2437                );
2438
2439            }
2440            
2441            // - if has parameters for fetching latest textbook parameters
2442            if ($latestPresetTextbookParams) {
2443                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
2444            }
2445
2446            // -  check sapuri ID
2447            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
2448                if (isset($lessonOnairLatestDataFlg)) {
2449                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2450                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
2451                    ) {
2452                        $hideTextbookChangeModal = 'true';
2453                    }
2454                } else {
2455                    if (
2456                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2457                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
2458                    ) {
2459                        $hideTextbookChangeModal = 'true';
2460                    }
2461                }
2462            }
2463
2464            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
2465
2466            $this->set('hideTextbookChangeModal', $hideTextbookChangeModal);
2467
2468            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
2469            if (
2470                $hideTextbookChangeModal == 'false'
2471                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
2472                && (isset($onGoingLesson) && $onGoingLesson == false)
2473            ) {
2474                $allTextbookParams = array(
2475                    'category_id' => $latestPresetTextbookConnect_categoryId, 
2476                    'connect_id' => $latestPresetTextbookConnect_id,
2477                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
2478                );
2479                
2480                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
2481                // if has next textbook chapter, show button 
2482                if (
2483                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
2484                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
2485                ) {
2486                    $enableNextTextbookChapterButton = 'true';
2487                }
2488            }
2489
2490            if(!empty($this->sharedUserData['User'])){
2491                // - campaing stamps
2492                $this->getActiveCampaignStampData();
2493            }
2494
2495            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
2496        }
2497
2498        //NJ-18780 : check the user total reservation if lite plan 
2499        $_user = $this->sharedUserData['User'] ?? array();
2500        $liteLimitReservationFlg = 0;
2501
2502        if (
2503            $_user && 
2504            in_array($_user['payment_plan_id'], Configure::read('lite_payment_plans'))
2505        ) {
2506            # fetch the total reservation 
2507            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $this->Auth->user('id')));
2508
2509            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
2510                # show modal
2511                $liteLimitReservationFlg = 1;
2512            }
2513        }
2514
2515        // NJ-18780 : set view 
2516        $this->set('liteLimitReservationFlg',$liteLimitReservationFlg);
2517
2518
2519        $this->set('chatHash', isset($chatHash) ? $chatHash : '');
2520    
2521        //-Live Lesson Phase 3
2522        $this->set('liveLessonFlg', $liveLessonFlg);
2523
2524        //NJ-33414
2525        $this->UsersDetail->openDBReplica();
2526        $fetchUsersDetail = $this->UsersDetail->find('first', array(
2527            'fields' => array(
2528                'lesson_request_flg'
2529            ),
2530            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
2531            'recursive' => -1
2532        ));
2533        $this->UsersDetail->closeDBReplica();
2534
2535        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
2536        $this->set('lessonRequestFlg',$lessonRequestFlg);
2537
2538        //-- NJ-44869 skip communication modal
2539        $lessonSystemTroubleFlg = 0;
2540        $hideConnectionModalFlg = 0;
2541
2542        if (!empty($chatHash)) {
2543            $memcached = new myMemcached();
2544            $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
2545    
2546            if (!empty($lessonSystemTroubleCache)) {
2547                $memcached->delete('lesson_system_trouble_' . $chatHash);
2548                $lessonSystemTroubleFlg = 1;
2549            } 
2550        }
2551        
2552        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
2553        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
2554    }
2555
2556    /**
2557     * @api {post} /user/waiting/getStrengthRating getStrengthRating()
2558     * @apiName getStrengthRating
2559     * @apiGroup Waiting
2560     * @apiDescription Retrieves the strength rating items for a specific teacher in Native Camp. It returns the list of strength rating items.
2561     *
2562     * @apiBody {String} teacherId The ID of the teacher.
2563     * 
2564     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2565     * @apiSuccess {Object[]} strengthItems The list of strength rating items.
2566     *
2567     * @apiSuccessExample {json} Success-Response:
2568     *     {
2569     *         "res": true,
2570     *         "strengthItems": [
2571     *             {
2572     *                 "id": 1,
2573     *                 "name": "Friendly",
2574     *                 "rating": 5
2575     *             }
2576     *         ]
2577     *     }
2578     *
2579     * @apiError {Boolean} res Indicates whether the request was successful.
2580     *
2581     * @apiErrorExample {json} Error-Response:
2582     *     {
2583     *         "res": false
2584     *     }
2585     * 
2586     * @apiSampleRequest off
2587     */
2588    public function getStrengthRating() {
2589        $this->autoRender = false;
2590        $this->layout = false;
2591        $response = json_encode(array('res' => false)); // default
2592
2593        if($this->request->is('post')) {
2594            $post = $this->request->data;
2595            if (!isset($post['teacherId']) && $post['teacherId']) {
2596                return json_encode($response);
2597            }
2598            $teacherId = $post['teacherId'];
2599            
2600            $strengthItemsParams = array(
2601                'teacherId' => $teacherId,
2602                'type' => 0,
2603                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)
2604            );
2605
2606            $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
2607            
2608            if(!empty($strengthItems) && $strengthItems) {
2609                $response = json_encode(array(
2610                    'res' => true, 
2611                    'strengthItems' => $strengthItems, 
2612                ));
2613            }
2614        }
2615        return $response;
2616
2617    }
2618
2619    /**
2620     * @api {post} /user/waiting/getLessonHistory getLessonHistory()
2621     * @apiName getLessonHistory
2622     * @apiGroup Waiting
2623     * @apiDescription Retrieves the lesson history for a specific teacher and user in Native Camp. It returns the details of the lessons, including textbook information and chat logs.
2624     *
2625     * @apiBody {String} teacherId The ID of the teacher.
2626     * @apiBody {Boolean} [avatar_flg=false] Indicates if the request is for avatar lessons.
2627     * 
2628     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2629     * @apiSuccess {Object[]} lessonHistory The list of lesson history.
2630     * @apiSuccess {Number} lessonHistory.lesson_number The lesson number.
2631     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in JP format.
2632     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
2633     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson.
2634     * @apiSuccess {String} lessonHistory.textbook_url The URL of the textbook.
2635     * @apiSuccess {String} lessonHistory.categoryNameLabel The category name of the textbook.
2636     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The subcategory name of the textbook.
2637     * @apiSuccess {String} lessonHistory.textbookNameLabel The name of the textbook.
2638     * @apiSuccess {Number} lessonHistory.rate The rating of the lesson.
2639     * @apiSuccess {String} lessonHistory.chat_logs_url The URL of the chat logs.
2640     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates if the lesson has message logs.
2641     * @apiSuccess {String} lessonHistory.message_logs_url The URL of the message logs.
2642     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
2643     * @apiSuccess {String} lessonHistory.textbook_image The image URL of the textbook.
2644     *
2645     * @apiSuccessExample {json} Success-Response:
2646     *     {
2647     *         "res": true,
2648     *         "lessonHistory": [
2649     *             {
2650     *                 "lesson_number": 1,
2651     *                 "chatStartJPDate": "2023-12-01",
2652     *                 "chatStartTime": "10:00",
2653     *                 "lessonHistoryTime": "30分",
2654     *                 "textbook_url": "/textbook/page-detail/1/123",
2655     *                 "categoryNameLabel": "Category Name",
2656     *                 "subCategoryNameLabel": "Subcategory Name",
2657     *                 "textbookNameLabel": "Textbook Name",
2658     *                 "rate": 5,
2659     *                 "chat_logs_url": "/chat-history/123/abc123",
2660     *                 "has_message_logs": true,
2661     *                 "message_logs_url": "/lesson-message/detail/1",
2662     *                 "audio_count_log": 3,
2663     *                 "textbook_image": "http://example.com/image.jpg"
2664     *             }
2665     *         ]
2666     *     }
2667     *
2668     * @apiError {Boolean} res Indicates whether the request was successful.
2669     *
2670     * @apiErrorExample {json} Error-Response:
2671     *     {
2672     *         "res": false
2673     *     }
2674     * 
2675     * @apiSampleRequest off
2676     */
2677    public function getLessonHistory($sp = false, $teacherId = null) {
2678        $this->autoRender = false;
2679        $this->layout = false;
2680        $response = json_encode(array('res' => false)); // default
2681        
2682        if($this->request->is('post') || $sp) {
2683            $post = $this->request->data;
2684            if (!isset($post['teacherId']) && $post['teacherId']) {
2685                return json_encode($response);
2686            }
2687            $teacherId = $post['teacherId'] ?? $teacherId;
2688            $teacherId = Sanitize::escape($teacherId);
2689
2690            $isAvatarFlg = (isset($post['avatar_flg']) && $post['avatar_flg']) ? true : false;
2691
2692            //NC-7984 start
2693            if($isAvatarFlg){
2694                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10, "avatar");
2695            }else{
2696                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10);
2697
2698            }
2699
2700            if(!empty($lesson_history_data) && $lesson_history_data) {
2701                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
2702
2703                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
2704                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
2705                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
2706
2707                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
2708
2709                    $lessonTime = $dteStart->diff($dteEnd);
2710                    $lessonHistoryTime = $lessonTime->format("%I");
2711
2712                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
2713
2714                    $categoryName = $value['TextbookCategory']['name'];
2715                    $subcategoryName = $value['TextbookSubategory']['name'];
2716                    $textbookName = $value['Textbook']['name'];
2717                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
2718
2719                    // - if has translated Category name
2720                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
2721                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
2722                    }
2723
2724                    // - if has translated subcategory name
2725                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
2726                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
2727                    }
2728
2729                    // - if has translated textbook name
2730                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
2731                        $textbookName = $value['GlobalTextbook']['gl_name'];
2732                    }
2733
2734                    // - set textbook name
2735                    $categoryNameLabel = $categoryName;
2736                    $subCategoryNameLabel = $subcategoryName;
2737                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
2738                    $textbookNameLabel = $textbookOrder . $textbookName;
2739                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
2740
2741                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
2742                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
2743                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
2744                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
2745
2746                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
2747                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
2748                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
2749                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
2750                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
2751                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
2752                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
2753                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
2754                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
2755                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
2756                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
2757                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
2758                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
2759                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
2760                }
2761                
2762                $response = json_encode(array(
2763                    'res' => true, 
2764                    'lessonHistory' => $lesson_history_data['lessonHistory']
2765                ));
2766
2767                if($sp) {
2768                    $response = $lesson_history_data['lessonHistory'];
2769                }
2770            }
2771            //NC-7984 end
2772        }
2773
2774        return $response;
2775
2776    }
2777
2778    /**
2779     * @api {post} /user/waiting/getPrimaryDetails getPrimaryDetails()
2780     * @apiName getPrimaryDetails
2781     * @apiGroup Waiting
2782     * @apiDescription Retrieves the primary details for a specific teacher in Native Camp. It returns the number of lessons, reservations, and comments for the teacher.
2783     *
2784     * @apiBody {String} teacherId The ID of the teacher.
2785     * 
2786     * @apiSuccess {Number} lessonCount The number of lessons for the teacher.
2787     * @apiSuccess {Number} reserveCount The number of reservations for the teacher.
2788     * @apiSuccess {Number} commentCount The number of comments for the teacher.
2789     *
2790     * @apiSuccessExample {json} Success-Response:
2791     *     {
2792     *         "lessonCount": 100,
2793     *         "reserveCount": 50,
2794     *         "commentCount": 20
2795     *     }
2796     *
2797     * @apiError {String} status The status of the request (NG).
2798     * @apiError {String} message The error message.
2799     *
2800     * @apiErrorExample {json} Error-Response:
2801     *     {
2802     *         "status": "NG",
2803     *         "message": "Invalid request."
2804     *     }
2805     * 
2806     * @apiSampleRequest off
2807     */
2808    public function getPrimaryDetails() {
2809        $this->autoRender = false;
2810        $this->layout = "";
2811        if (!$this->request->is('ajax')) { return ; }
2812        
2813        $teacherId = $this->request->data['teacherId'];
2814        $teacherId = Sanitize::escape($teacherId);
2815        
2816        if (empty($teacherId)) { return ; }
2817
2818        //number of lesson for all child accounts
2819        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
2820        //number of reservation for all child accounts
2821        $reserveCount = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId, 'avatar' => 1));
2822
2823        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
2824        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
2825        $options['language_id'] = $reviewLanguage[0];
2826        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
2827        $options['isAvatar'] = 1;
2828
2829        $userTable = new UserTable($this->Auth->user());
2830        $sapuriPlan = $userTable->isStudySapuri();
2831        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
2832        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
2833            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
2834        } else {
2835            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
2836        }
2837
2838        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
2839        $results = [
2840            'lessonCount' => $lessonCount,
2841            'reserveCount' => $reserveCount,
2842            'commentCount' => $commentCount,
2843        ];
2844
2845        echo json_encode($results);
2846        return;
2847    }
2848
2849    /**
2850     * @api {post} /user/waiting/getFavCount getFavCount()
2851     * @apiName getFavCount
2852     * @apiGroup Waiting
2853     * @apiDescription Retrieves the favorite count for a specific teacher in Native Camp. It returns the total number of favorites and whether the current user has favorited the teacher.
2854     *
2855     * @apiBody {String} teacherId The ID of the teacher.
2856     * 
2857     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2858     * @apiSuccess {Number} favCount The total number of favorites for the teacher.
2859     * @apiSuccess {Number} isFav Indicates whether the current user has favorited the teacher (1: Yes, 0: No).
2860     *
2861     * @apiSuccessExample {json} Success-Response:
2862     *     {
2863     *         "res": true,
2864     *         "favCount": 10,
2865     *         "isFav": 1
2866     *     }
2867     *
2868     * @apiError {Boolean} res Indicates whether the request was successful.
2869     *
2870     * @apiErrorExample {json} Error-Response:
2871     *     {
2872     *         "res": false
2873     *     }
2874     * 
2875     * @apiSampleRequest off
2876     */
2877    public function getFavCount() {
2878        $this->autoRender = false;
2879        $this->layout = false;
2880        $response = json_encode(array('res' => false)); // default
2881
2882        if($this->request->is('post')) {
2883            $post = $this->request->data;
2884            if (!isset($post['teacherId']) && $post['teacherId']) {
2885                return json_encode($response);
2886            }
2887            $teacherId = $post['teacherId'];
2888
2889            $favCount = $this->UsersFavorite->find('count', array(
2890                'conditions' => array(
2891                    'UsersFavorite.teacher_id'  => $teacherId
2892                )
2893            ));
2894
2895            $isFav = $this->UsersFavorite->find('count', array(
2896                'conditions' => array(
2897                    'UsersFavorite.user_id'     => $this->Auth->user('id'),
2898                    'UsersFavorite.teacher_id'     => $teacherId,
2899                )
2900            ));
2901
2902            if ($favCount){
2903                $response = json_encode(array('res' => true, 'favCount' => $favCount, 'isFav' => $isFav));
2904            }
2905        }
2906        return $response;
2907    }
2908
2909    /**
2910     * @api {post} /user/waiting/getAlbum getAlbum()
2911     * @apiName getAlbum
2912     * @apiGroup Waiting
2913     * @apiDescription Retrieves the album of images for a specific teacher in Native Camp. It returns the list of approved images for the teacher.
2914     *
2915     * @apiBody {String} teacherId The ID of the teacher.
2916     * 
2917     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2918     * @apiSuccess {Object[]} [albums] The list of albums (only if the request was successful).
2919     * @apiSuccess {Number} albums.id The ID of the teacher image.
2920     * @apiSuccess {Number} albums.teacher_id The ID of the teacher.
2921     * @apiSuccess {Number} albums.approve_flg The approval flag of the image.
2922     * @apiSuccess {Number} albums.is_profile Indicates if the image is a profile image.
2923     * @apiSuccess {Number} albums.approve_required Indicates if the image requires approval.
2924     * @apiSuccess {String} albums.url The URL of the image.
2925     *
2926     * @apiSuccessExample {json} Success-Response:
2927     *     {
2928     *         "res": true,
2929     *         "albums": [
2930     *             {
2931     *                 "id": 1,
2932     *                 "teacher_id": 123,
2933     *                 "approve_flg": 1,
2934     *                 "is_profile": 0,
2935     *                 "approve_required": 0,
2936     *                 "url": "http://example.com/image.jpg"
2937     *             }
2938     *         ]
2939     *     }
2940     *
2941     * @apiError {Boolean} res Indicates whether the request was successful.
2942     *
2943     * @apiErrorExample {json} Error-Response:
2944     *     {
2945     *         "res": false
2946     *     }
2947     * 
2948     * @apiSampleRequest off
2949     */
2950    public function getAlbum() {
2951        $this->autoRender = false;
2952        $this->layout = false;
2953        $response = json_encode(array('res' => false)); // default
2954
2955        if($this->request->is('post')) {
2956            $post = $this->request->data;
2957            if (!isset($post['teacherId']) && $post['teacherId']) {
2958                return json_encode($response);
2959            }
2960            $teacherId = $post['teacherId'];
2961
2962            $this->TeacherImage->openDBReplica();
2963            $album = $this->TeacherImage->find('all', array(
2964                'fields' => array(
2965                    'TeacherImage.id',
2966                    'TeacherImage.teacher_id',
2967                    'TeacherImage.approve_flg',
2968                    'TeacherImage.is_profile',
2969                    'TeacherImage.approve_required',
2970                    'FileStorage.url'
2971                ),
2972                'conditions' => array(
2973                    'TeacherImage.teacher_id' => $teacherId,
2974                    'TeacherImage.is_profile' => 0,
2975                    'OR' => array(
2976                        'OR' => array(
2977                            'TeacherImage.approve_flg' => 1,
2978                            'TeacherImage.approve_required' => 0,
2979                        )
2980                    )
2981                ),
2982                'joins' => array(
2983                    array(
2984                        'type' => 'INNER',
2985                        'table' => 'file_storage',
2986                        'alias' => 'FileStorage',
2987                        'conditions' => array(
2988                            'TeacherImage.file_storage_id = FileStorage.id',
2989                            'FileStorage.uploader_type = 3',
2990                            'FileStorage.uploader_id' => $teacherId
2991                        )
2992                    )
2993                ),
2994                'order' => array('TeacherImage.id DESC')
2995            ));
2996            $this->TeacherImage->closeDBReplica();
2997
2998            if ($album){
2999                $response = json_encode(array('res' => true, 'albums' => $album));
3000            }
3001        }
3002        return $response;
3003    }
3004    
3005
3006    // NJ-3786 - arrange teacher data
3007    private function arrangeTeacherRecommendList( $params = array() ){
3008        $result = array();
3009        $data = isset( $params['data'] ) && $params['data'] ? $params['data'] : null;
3010        $userId = isset( $params['user_id'] ) && $params['user_id'] ? $params['user_id'] : null;
3011        $userData = isset($params['user_data']) && $params['user_data'] ?  $params['user_data'] : null;
3012        $nativeLanguage = isset($userData['native_language2']) && $userData['native_language2'] ?  $userData['native_language2'] : null;
3013        $platformArrangeApiList = (isset($params['platform_arrange']) && $params['platform_arrange'] == 'api') ;
3014        $categoryId = isset($params['category_id']) && $params['category_id'] ?  $params['category_id'] : null;
3015        $classStatusArr = Configure::read('teacher_lamp_color_class');
3016        $textbookImagUrl = null;
3017        if($categoryId){
3018            // Fetch textbook image
3019            $textbookParams = array(
3020                'conditions' => array('TextbookCategory.id' => $categoryId ),
3021                'fields' => array('TextbookCategory.image_big_url'),
3022                'recursive' => -1
3023            );
3024            ClassRegistry::init('TextbookCategory')->openDBReplica();
3025            $fetchTextbookData = ClassRegistry::init('TextbookCategory')->find('first',$textbookParams);
3026            ClassRegistry::init('TextbookCategory')->closeDBReplica();
3027            if($fetchTextbookData && isset($fetchTextbookData['TextbookCategory']['image_big_url']) && $fetchTextbookData['TextbookCategory']['image_big_url'] ){
3028                $textbookImagUrl = $fetchTextbookData['TextbookCategory']['image_big_url'];
3029            }
3030        }
3031
3032        if($data){
3033            foreach( $data as $index => $val ) {
3034                $teacherDetail = new TeacherTable($val['Teacher']);
3035                // - get countries
3036                $countries = strtolower($val['CountryCode']['country_name']);
3037                $explodeCountries = explode(' ', $countries);
3038                $implode = implode('_',$explodeCountries);
3039
3040                // - country name
3041                $countryName = $val['CountryCodeDetails']['country_name'] ? $val['CountryCodeDetails']['country_name'] : $val['CountryCode']['country_name'];
3042
3043                // - get residency
3044                $recidency = strtolower($countryName);
3045                $explodeRecidency = explode(' ', $recidency);
3046                $implodeResidency = implode('_',$explodeRecidency);
3047
3048                // - nationality
3049                $arrNationalityInfo = array(
3050                    "id" => "",
3051                    "name" => $val['CountryCode']['country_name'],
3052                    "flag" => $implode
3053                );
3054
3055                // - residence info
3056                $arrResidenceInfo = array(
3057                    "id" => "",
3058                    "name" => $countryName,
3059                    "flag" => $implodeResidency
3060                );
3061
3062                $getUserSettingLanguage = $nativeLanguage && $nativeLanguage == 'ja' ? $teacherDetail->jp_name : $teacherDetail->name ;
3063
3064                if( $platformArrangeApiList ) {
3065                    $result[$index] = array(
3066                        "id" => $teacherDetail->id,
3067                        "name" => $getUserSettingLanguage,
3068                        "name_ja" => $teacherDetail->jp_name,
3069                        "name_eng" => $teacherDetail->name,
3070                        "rating" => isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : 0,
3071                        "lessons" => isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0,
3072                        "favorite_count" => $this->UsersFavorite->getFavoriteCount($teacherDetail->id),
3073                        "age" => isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0,
3074                        "nationality_id" =>(int)$val['CountryCode']['id'],
3075                        "image_main" =>  $teacherDetail->getImageUrl(),
3076                        // - country, residence info
3077                        'residence_image' =>  FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png",
3078                        'residence_name' => __d('default',$arrResidenceInfo["name"]),
3079                        'country_name' => __d('default',$arrNationalityInfo["name"]),
3080                        'country_image' =>  FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png",
3081                        'textbook_image_url' =>  $textbookImagUrl
3082                    );
3083                } else {
3084                    $result[$index]['Teacher'] = $val['Teacher'];
3085                    $result[$index]['Teacher']['lesson_count'] = isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0;
3086                    $result[$index]['Teacher']['favorite_count'] = $this->UsersFavorite->getFavoriteCount($teacherDetail->id);
3087                    $result[$index]['Teacher']['age'] = isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0;
3088                    $result[$index]['Teacher']['evaluation_average'] = isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : __d('waiting', '集計中');
3089                    $result[$index]['Teacher']['image_url'] = $teacherDetail->getImageUrl();
3090                    $result[$index]['Teacher']['residence_image'] = FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png";
3091                    $result[$index]['Teacher']['residence_name'] = __d('default',$arrResidenceInfo["name"]);
3092                    $result[$index]['Teacher']['country_name'] = __d('default',$arrNationalityInfo["name"]);
3093                    $result[$index]['Teacher']['country_image'] = FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png";
3094                    $result[$index]['Teacher']['textbook_image_url'] = $textbookImagUrl;
3095                }
3096            }
3097        }
3098
3099        return $result;
3100
3101    }
3102
3103    //not sued function
3104    public function checkReservation($teacher, $onair_status) {
3105
3106        // 定数 取得 (category=26)
3107        $getDefineMaster = $this->DefineMaster->getDefine('26');
3108        // 入室できる時間(n分前)
3109        $DefinePossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3110        // レッスンできる時間(n分前)
3111        $DefineLessonPossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3112        $reserver = 0;
3113
3114        $floored_seconds = floor(time() / (30 * 60)) * (30 * 60);
3115        $ceiled_seconds = ceil(time() / (30 * 60)) * (30 * 60);
3116        // 予約状況を取得
3117        $this->LessonSchedule->recursive = -1;
3118        $getLessonSchedule = $this->LessonSchedule->getLessonSchedule(date('Y-m-d H:i:s', $floored_seconds), date('Y-m-d H:i:s', $ceiled_seconds), $teacher->id, 'asc');
3119
3120        // 予約がある
3121        if(!empty($getLessonSchedule)) {
3122            $LessonSchedule = new LessonScheduleTable($getLessonSchedule[0]["LessonSchedule"]);
3123
3124            // 入室できる時間
3125            $possible_time = strtotime("- " . $DefinePossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3126
3127            // 予約時間
3128            $reservation_time = strtotime($LessonSchedule->lesson_time);
3129
3130            // レッスン可能な時間($lesson_possible_timeまで)
3131            $lesson_possible_time = strtotime("- " . $DefineLessonPossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3132
3133            // 予約しているユーザのID
3134            $userID = $getLessonSchedule[0]['LessonSchedule']["user_id"];  //not used user id . undefined variable $getLessonSchedule
3135
3136            // 予約があっても 定数(category=26, sub_category=1)分前なら入室できる
3137            if(time() <= $possible_time && $onair_status == 1) {
3138                // 予約時間
3139                $this->set('ReservationTime', date('H:i', $reservation_time));
3140                // レッスン可能時間
3141                $this->set('PossibleTime',  date('H:i', $lesson_possible_time));
3142            }
3143
3144            # get minute now
3145            $minuteNow = (int) date("i");
3146
3147            // 予約してる人は自分
3148            if (
3149                $userID == $this->Auth->user('id') &&
3150                $onair_status == 2 &&
3151                !(
3152                    ($minuteNow >= 56 && $minuteNow <= 59) ||
3153                    ($minuteNow >= 26 && $minuteNow <= 29)
3154                )
3155            ) {
3156                $reserver = 1;
3157            }
3158        }
3159
3160        $this->set('isReserved', $reserver);
3161    }
3162
3163    /**
3164     * @api {get} /user/waiting/start/:teacher_id/:free_flg/:class_id/:chapter_id/:textbook_type start()
3165     * @apiName start
3166     * @apiGroup Waiting
3167     * @apiDescription Starts a lesson for a specific teacher and user in Native Camp. It checks various conditions and redirects to the appropriate page.
3168     *
3169     * @apiParam {String} teacher_id The ID of the teacher.
3170     * @apiParam {String} [free_flg=null] The free flag.
3171     * @apiParam {String} [class_id=1] The ID of the class.
3172     * @apiParam {String} [chapter_id=1] The ID of the chapter.
3173     * @apiParam {String} [textbook_type=null] The type of the textbook.
3174     * 
3175     * @apiSuccess {String} redirect_url The URL to which the user is redirected.
3176     *
3177     * @apiSuccessExample {json} Success-Response:
3178     *     {
3179     *         "redirect_url": "/class/index/123/1/1/1/1"
3180     *     }
3181     *
3182     * @apiError {String} status The status of the request (NG).
3183     * @apiError {String} message The error message.
3184     *
3185     * @apiErrorExample {json} Error-Response:
3186     *     {
3187     *         "status": "NG",
3188     *         "message": "Invalid request."
3189     *     }
3190     * 
3191     * @apiSampleRequest off
3192     */
3193    public function start($teacher_id, $free_flg=null, $class_id = null, $chapter_id = null, $textbook_type = null) {
3194        $this->autoRender = false;
3195        App::uses('myTools','Lib');
3196
3197        if (!$class_id)   $class_id     = 1;
3198        if (!$chapter_id) $chapter_id = 1;
3199
3200        if (is_null($teacher_id)) {
3201            return $this->redirect('/waiting/');
3202        }
3203        $data = $this->Teacher->findById($teacher_id);
3204        if (!$data) {
3205            return $this->redirect('/waiting/');
3206        }
3207
3208        /*
3209        * added in issue NC-488
3210        * check whether the user has been blocked already or not
3211        */
3212        //NJ-65055: params for checking teacher is hidden
3213        $isTeacherHiddenParams = array(
3214            'user_id' => $this->Auth->user('id'),
3215            'teacher_id' => $teacher_id
3216        );
3217
3218        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacher_id) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
3219            return $this->redirect('/waiting/'); exit;
3220        }
3221
3222        // onairデータの中の講師IDがない
3223        $onAir = $this->LessonOnair->findByTeacherId($teacher_id);
3224        if (!isset($onAir['LessonOnair'])) {
3225            return $this->redirect('/');
3226        }
3227
3228        // レッスン中の場合
3229        if (!empty($onAir['LessonOnair']['status']) && $onAir['LessonOnair']['status']==3) {
3230            return $this->redirect('/waiting/detail/' . $teacher_id);
3231        }
3232
3233        // Overlapping reservation bug
3234        $lesson_available = $this->LessonSchedule->checkLessonAvailable($this->Auth->user('id'), $teacher_id);
3235        if (!$lesson_available) {
3236            return $this->redirect('/waiting/detail/' . $teacher_id);
3237        }
3238
3239
3240        $onAirId = $onAir['LessonOnair']['id'];
3241
3242        $this->Session->write('proceedFlag.clicked', 'true');
3243        return $this->redirect('/class/index/' . $teacher_id . '/' . $free_flg . '/' . $class_id . '/' . $chapter_id . '/' . $textbook_type);
3244    }
3245
3246    /**
3247     * @api {post} /user/waiting/teacherReserveList teacherReserveList()
3248     * @apiName teacherReserveList
3249     * @apiGroup Waiting
3250     * @apiDescription Retrieves the reservation list for a specific teacher in Native Camp. It returns various information about the available reservation slots, user eligibility, and more.
3251     *
3252     * @apiBody {String} teacherId The ID of the teacher.
3253     * @apiBody {Boolean} [counselingFlg=0] Indicates if the request is for counseling.
3254     * @apiBody {String} [hash16] The hash16 value for the user.
3255     * @apiBody {Number} [timeDiff=0] The time difference in seconds.
3256     * @apiBody {Boolean} [reservationHideFlg=false] Indicates if the reservation slots should be hidden.
3257     * @apiBody {Boolean} [hideLimitedPlanReservation=null] Indicates if the limited plan reservations should be hidden.
3258     * @apiBody {Number} [teacherCoin=0] The coin value for the teacher.
3259     * @apiBody {Number} [sapuriCoin=0] The coin value for Sapuri.
3260     * 
3261     * @apiSuccess {Object[]} days The list of days for the reservation slots.
3262     * @apiSuccess {String} days.Y The year.
3263     * @apiSuccess {String} days.m The month.
3264     * @apiSuccess {String} days.d The day.
3265     * @apiSuccess {String} days.w The day of the week.
3266     * @apiSuccess {String} days.reserve_range The reservation range for the day.
3267     * @apiSuccess {Boolean} days.canUseCoupon Indicates if a coupon can be used for the reservation.
3268     * @apiSuccess {Object[]} times The list of times for the reservation slots.
3269     * @apiSuccess {Object} reserved The reserved slots.
3270     * @apiSuccess {String} user_id The ID of the user.
3271     * @apiSuccess {Number} userCardCompany The card company of the user.
3272     * @apiSuccess {Number} timeDiff The time difference in seconds.
3273     * @apiSuccess {Object} reservedTz The reserved slots with timezone adjustments.
3274     * @apiSuccess {Boolean} limitedPlanAvailable Indicates if the limited plan reservation is available.
3275     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
3276     * @apiSuccess {Boolean} notCorporateLightTeachers Indicates if the teacher is not a corporate light teacher.
3277     * @apiSuccess {Boolean} corporateLightUser Indicates if the user is a corporate light user.
3278     * @apiSuccess {Boolean} corporateLimitedUser Indicates if the user is a corporate limited user.
3279     * @apiSuccess {Object} teacherInfo The information of the teacher.
3280     * @apiSuccess {Object} campaignPeriod The campaign period information.
3281     * @apiSuccess {Object} discountCampaignPeriod The discount campaign period information.
3282     * @apiSuccess {String} currentUserTime The current user time.
3283     * @apiSuccess {String} currentUtcOffset The current UTC offset.
3284     * @apiSuccess {Boolean} isShowCancellationAlert Indicates if the cancellation alert should be shown.
3285     * @apiSuccess {Object[]} otherReservations The list of other reservations.
3286     * @apiSuccess {Boolean} viewSlotForSapuri Indicates if the slot is for Sapuri.
3287     * @apiSuccess {String} studySapuriId The ID of the study Sapuri.
3288     * @apiSuccess {Object[]} lessonRequestSlot The list of lesson request slots.
3289     * @apiSuccess {Boolean} lessonRequestInvalidPlan Indicates if the lesson request plan is invalid.
3290     * @apiSuccess {String} teacherId The ID of the teacher.
3291     * @apiSuccess {Number} callanOption Indicates if the Callan option is available.
3292     * @apiSuccess {Object} user The user information.
3293     * @apiSuccess {Object} teacherData The teacher data.
3294     * @apiSuccess {String[]} weekday The list of weekdays.
3295     * @apiSuccess {Object} hiddenReservedTz The hidden reserved slots with timezone adjustments.
3296     * @apiSuccess {Boolean} canLive Indicates if the user can join live lessons.
3297     * @apiSuccess {Boolean} normalLitePlanCanReserveFlg Indicates if the normal lite plan can reserve.
3298     * @apiSuccess {Boolean} isNormalLitePlan Indicates if the user is on a normal lite plan.
3299     * @apiSuccess {Boolean} notNormalLitePlanTeacher Indicates if the teacher is not a normal lite plan teacher.
3300     * @apiSuccess {Boolean} teacherCoinDisableSlots Indicates if the teacher coin disables slots.
3301     * @apiSuccess {Boolean} excludeLessonRequestDiscount Indicates if the lesson request discount should be excluded.
3302     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
3303     * @apiSuccess {Boolean} notNewCampaignEligible Indicates if the user is not eligible for the new campaign.
3304     * @apiSuccess {String} teacherImageSrc The image URL of the teacher.
3305     * @apiSuccess {String} teacherName The name of the teacher.
3306     *
3307     * @apiSuccessExample {json} Success-Response:
3308     *     {
3309     *         "days": [
3310     *             {
3311     *                 "Y": "2023",
3312     *                 "m": "12",
3313     *                 "d": "01",
3314     *                 "w": "(金)",
3315     *                 "reserve_range": "10:00~11:00",
3316     *                 "canUseCoupon": true
3317     *             }
3318     *         ],
3319     *         "times": ["10:00", "10:30", "11:00"],
3320     *         "reserved": {...},
3321     *         "user_id": "123",
3322     *         "userCardCompany": 1,
3323     *         "timeDiff": 0,
3324     *         "reservedTz": {...},
3325     *         "limitedPlanAvailable": true,
3326     *         "hideLimitedPlanReservation": false,
3327     *         "notCorporateLightTeachers": false,
3328     *         "corporateLightUser": true,
3329     *         "corporateLimitedUser": false,
3330     *         "teacherInfo": {...},
3331     *         "campaignPeriod": {...},
3332     *         "discountCampaignPeriod": {...},
3333     *         "currentUserTime": "2023/12/01 10:00",
3334     *         "currentUtcOffset": "+09:00",
3335     *         "isShowCancellationAlert": true,
3336     *         "otherReservations": [...],
3337     *         "viewSlotForSapuri": true,
3338     *         "studySapuriId": "sapuri123",
3339     *         "lessonRequestSlot": [...],
3340     *         "lessonRequestInvalidPlan": false,
3341     *         "teacherId": "456",
3342     *         "callanOption": 1,
3343     *         "user": {...},
3344     *         "teacherData": {...},
3345     *         "weekday": ["(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)"],
3346     *         "hiddenReservedTz": {...},
3347     *         "canLive": true,
3348     *         "normalLitePlanCanReserveFlg": true,
3349     *         "isNormalLitePlan": true,
3350     *         "notNormalLitePlanTeacher": false,
3351     *         "teacherCoinDisableSlots": false,
3352     *         "excludeLessonRequestDiscount": false,
3353     *         "lessonRequestFlg": 1,
3354     *         "notNewCampaignEligible": false,
3355     *         "teacherImageSrc": "http://example.com/image.jpg",
3356     *         "teacherName": "John Doe"
3357     *     }
3358     *
3359     * @apiError {String} status The status of the request (NG).
3360     * @apiError {String} message The error message.
3361     *
3362     * @apiErrorExample {json} Error-Response:
3363     *     {
3364     *         "status": "NG",
3365     *         "message": "Invalid request."
3366     *     }
3367     * 
3368     * @apiSampleRequest off
3369     */
3370    public function teacherReserveList() {
3371        $this->layout = "";
3372
3373        if (!$this->request->is('post')) {
3374            return ;
3375        }
3376
3377        $data = $this->request->data;
3378        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : null;
3379        $counselingFlg = isset($data['counselingFlg']) ? $data['counselingFlg'] : 0;
3380        $hash16 = isset($data['hash16']) ? $data['hash16'] : null;
3381        $timeDiff = isset($data['timeDiff']) ? $data['timeDiff'] : 0;
3382        $reservationHideFlg = isset($data['reservationHideFlg']) ? $data['reservationHideFlg'] : false;
3383        $hideLimitedPlanReservation = isset($data['hideLimitedPlanReservation']) ? $data['hideLimitedPlanReservation'] : null;
3384        $teacherCoin = isset($data['teacherCoin']) ? $data['teacherCoin'] : 0;
3385        $sapuriCoin = isset($data['sapuriCoin']) ? $data['sapuriCoin'] : 0;
3386        $viewSlotForSapuri = false;
3387
3388        if (empty($teacherId)) {
3389            return ;
3390        }
3391
3392        $userId = $this->Auth->user('id');
3393        $teacher = ClassRegistry::init('Teacher')->getTeacherInfo($teacherId);
3394        $teacherInfo = $teacher['Teacher'];
3395        $userLanguage =  !empty($this->Auth->user('native_language2')) ? $this->Auth->user('native_language2') :Configure::read('default.user_language');
3396
3397        $this->User->recursive = -1;
3398        $user = $this->User->findById($userId);
3399
3400        // NJ-18780 : set var if callan half price teacher 
3401        $_isCallanHalfTeacher = (int) $teacherInfo['callan_halfprice_flg'];
3402
3403        if (
3404            $this->sharedUserData && 
3405            $this->isStudySapuriUser && 
3406            $sapuriCoin && 
3407            $teacherCoin <= $sapuriCoin
3408        ) {
3409            $viewSlotForSapuri = true;
3410            $userObj = new UserTable($this->sharedUserData['User']);
3411            $plan = $userObj->isStudySapuri();
3412            
3413            //NJ-10847 Hide Slots if Teacher has no Sapuri Textbook Badge
3414            $badgeParams = array('plan' => $plan, 'teacher_id' => $teacherId);
3415            $badges = TeacherBadgeTable::getSapuriStudentAndTeacherBadge($badgeParams);
3416            if (!$badges) {
3417                $viewSlotForSapuri = false;
3418            }
3419        }
3420
3421        // Hide reservations slot if lite plan and reservation coin is 0 
3422        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3423            $reservationHideFlg = true;
3424        }
3425
3426        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3427        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3428
3429        $times = array();
3430        $utcMin = explode(':', $this->utcOffset);
3431        if ($utcMin[1] == "45") {
3432            for ($i=0; $i<=23; $i++) {
3433                $times[] = sprintf("%02d",$i) . ':15';
3434                $times[] = sprintf("%02d",$i) . ':45';
3435            }
3436        } else {
3437            for ($i=0; $i<=23; $i++) {
3438                $times[] = sprintf("%02d",$i) . ':00';
3439                $times[] = sprintf("%02d",$i) . ':30';
3440            }
3441        }
3442
3443        $days = array();
3444
3445        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
3446            $weekday = array( __dx('waiting', 'day_three_letter', '(日)'), __dx('waiting', 'day_three_letter','(月)'), __dx('waiting', 'day_three_letter','(火)'), __dx('waiting', 'day_three_letter','(水)'), __dx('waiting', 'day_three_letter','(木)'), __dx('waiting', 'day_three_letter','(金)'), __dx('waiting', 'day_three_letter','(土)') );
3447        } else { // if the language is not Custom language format
3448            $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
3449        }
3450
3451        $reserved = array();
3452        // if reservation_hide_flg, display open reservation slots
3453        
3454        // 予約状況を取得
3455        // ~ hide slots if teacher reservation hide flg is true
3456        if (!$reservationHideFlg) {
3457            $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3458                $userId,
3459                $teacherId,
3460                date('Ymd', time()),
3461                date('Ymd', strtotime("+8 days", time())),
3462                false,
3463                $reservationHideFlg
3464            );
3465        }
3466
3467        // // overide reserved for campaign hide slots for not eligeble users
3468        // if ($reservationCampaignHideFlg && isset($campaignDiscountFlg) && $campaignDiscountFlg) {
3469        //     $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3470        //         $userId,
3471        //         $teacherId,
3472        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['start_date'])),
3473        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['end_date'])),
3474        //         false,
3475        //         $reservationCampaignHideFlg
3476        //     );
3477        // }
3478        
3479        // if have own reserved or available slot, check for live lesson slot
3480        $liveShift = array();
3481        $liveShiftLessonTimeData = [];
3482        if ($reserved) {
3483            $this->ShiftWorkOn->openDBReplica();
3484            $liveShift = $this->ShiftWorkOn->find('all', array(
3485                'fields' => ['ShiftWorkOn.lesson_time','DATE_FORMAT(ShiftWorkOn.lesson_time, \'%Y%m%d%H%i%S\') AS time'],
3486                'conditions' => array(
3487                    'ShiftWorkOn.teacher_id' => $teacherId,
3488                    'ShiftWorkOn.live_lesson_flg' => 1,
3489                    'ShiftWorkOn.hide_flg' => 0,
3490                    'ShiftWorkOn.lesson_time >= NOW()'
3491                ),
3492                'recursive' => -1
3493            ));
3494            $this->ShiftWorkOn->closeDBReplica();
3495
3496            $canLive = true;
3497            if ($liveShift) {
3498                if ($this->sharedUserData) {
3499                    $canLive = UserTable::canDoLiveViewing($this->sharedUserData['User']);
3500                }
3501                foreach ($liveShift as $shift) {
3502
3503                    if( isset($shift['ShiftWorkOn']['lesson_time']) && $shift['ShiftWorkOn']['lesson_time'] ) {
3504                        $liveShiftLessonTimeData[] = $shift['ShiftWorkOn']['lesson_time'];
3505                    }
3506
3507                    if ( empty($reserved[$shift[0]['time']]) ) {
3508                        continue;
3509                    }
3510
3511                    //-- open for live lesson resevation
3512                    if ( $reserved[$shift[0]['time']] == 9 ) {
3513                        if (!$canLive) {
3514                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3515                        } else {
3516                            $reserved[$shift[0]['time']] = 10;         //-- available live
3517                        }
3518
3519                    //-- own live lesson reservation
3520                    } elseif ( $reserved[$shift[0]['time']] == 2 ) {
3521                        $reserved[$shift[0]['time']] = 11;
3522
3523                    //-- other student live lesson reservation
3524                    } elseif ( $reserved[$shift[0]['time']] == 1 ) {
3525                        if (!$canLive) {
3526                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3527                        } else {
3528                            $reserved[$shift[0]['time']] = 12;         //-- reserved by another
3529                        }
3530                    }
3531                }
3532            }
3533        }
3534
3535        // Check if sapuri user and with in campaign's duration (sicth anniv, christmas)
3536        $ifSapuriAndCampaign = false;
3537        $sixthAnnivCampaignDateArr = Configure::read('campaign_config.sixth_anniv_1.period');
3538        // $christmasDateArr = Configure::read('campaign_config.christmas.period');
3539        // $goldenWeekDateArr = Configure::read('campaign_config.christmas.period');
3540        if (
3541            (
3542                (time() >= strtotime($sixthAnnivCampaignDateArr['start']) && time() <= strtotime($sixthAnnivCampaignDateArr['end']))
3543                // || (time() >= strtotime($christmasDateArr['start']) && time() <= strtotime($christmasDateArr['end']))
3544                // || (time() >= strtotime($goldenWeekDateArr['start']) && time() <= strtotime($goldenWeekDateArr['end']))
3545            )
3546            && $this->studySapuriId
3547        ) {
3548            $ifSapuriAndCampaign = true;
3549        }
3550        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3551        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3552
3553        //campaign period start and end time
3554        $campaignPeriod = null;
3555        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3556            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
3557                'user_id' => $this->Auth->user('id'),
3558                'teacher_id' => $teacherId,
3559                'bypass_count' => $forceFetchCampaignPeriod
3560            ));
3561        }
3562
3563        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3564            $discountcampaignPeriod = $this->CampaignInstructor->fetchNewCampaignPeriod(array(
3565                'user_id' => $this->Auth->user('id'),
3566                'teacher_id' => $teacherId,
3567                'bypass_count' => $forceFetchCampaignPeriod
3568            ));
3569        }
3570
3571        //NJ-28004 get current reservation
3572        $currentReseervations = $this->LessonSchedule->getCurrentTeacherReservation($teacherId, $userId);
3573
3574        //NC-3787 - get all users reservation except for current teacher
3575        $otherReservations = $this->LessonSchedule->getOtherReservationsExcept($teacherId, $userId);
3576        $reservedDate = '';
3577        $reservedTz = array();
3578        $teacherData = array();
3579        $reservedArr = is_array($reserved) ? $reserved : [];
3580
3581        $allLessonTimes = array_unique(array_merge(
3582            array_map(function($reservedData) {
3583                return date('Y-m-d H:i:s', strtotime($reservedData));
3584            }, array_keys($reservedArr)),
3585            $otherReservations,
3586            $currentReseervations
3587        ));
3588
3589        $allLessonTimes = is_array($allLessonTimes) ? $allLessonTimes : [];
3590        $lessonTimesParams = array(
3591            'lesson_times' => $allLessonTimes,
3592            'teacher_id' => $teacherId,
3593            'user_id' => $userId,
3594            'localize_dir' => $this->localizeDir,
3595            'campaign' => $discountcampaignPeriod
3596        );
3597
3598        $allReservationsData = $this->LessonSchedule->getAllReservationData($lessonTimesParams);
3599
3600        if (is_iterable($reserved)) {
3601            foreach($reserved as $key => $val) {
3602
3603                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3604                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($key));
3605                $campaignPeriod['lesson_time'] = $reservedLessonTime;
3606                $discountcampaignPeriod['lesson_time'] = $reservedLessonTime;
3607                $inCampaign = false;
3608                $inNewCampaign = false;
3609
3610                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3611                    $inNewCampaign = true;
3612                }
3613
3614                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3615                    $inNewCampaign = true;
3616                }
3617
3618                if( $liveShiftLessonTimeData && in_array($reservedLessonTime,$liveShiftLessonTimeData) ) {
3619                    $teacherSlotEvent = Configure::read('reservation_event_type.live_lesson');
3620                } elseif( $inCampaign ) {
3621                    $teacherSlotEvent = Configure::read('reservation_event_type.popular_campaign');
3622                }elseif( $inNewCampaign ) {
3623                    $teacherSlotEvent = Configure::read('reservation_event_type.discount_campaign');
3624                }
3625
3626                $teacherData = in_array($reservedLessonTime, $otherReservations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3627                $currentTeacherData = in_array($reservedLessonTime, $currentReseervations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3628
3629                $reservedDatas = [
3630                    'reserved' => $key,
3631                    'val' => $val,
3632                    'reservation_event' => $teacherSlotEvent,
3633                    'teacherData' => $teacherData,
3634                    'currentTeacherData' => $currentTeacherData
3635                ];
3636
3637                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3638                $reservedTz[$timeKeySlot] = $reservedDatas;
3639
3640                $currentDate = substr($key, 0,8);
3641                $min = date('i', strtotime($key));
3642                $hour = intval(date('H', strtotime($key)));
3643                if ($min == '30') {
3644                    $hour = $hour + 1;
3645                    $min = ":00";
3646                } else {
3647                    $min = ":30";
3648                }
3649                if ($reservedDate != $currentDate) {
3650                    if (!isset($reservedRange[$currentDate][0])) {
3651                        $reservedRange[$currentDate][0] = date('H:i', strtotime($key));
3652                        $reservedRange[$currentDate][1] = strval($hour).$min;
3653                    } else {
3654                        $reservedRange[$currentDate][1] = strval($hour).$min;
3655                    }
3656                } else {
3657                    $reservedRange[$currentDate][1] = strval($hour).$min;
3658                }
3659                $rKeys = array_keys($reservedRange);
3660                $rLastKey = end($rKeys);
3661                $reservedDate = $rLastKey;
3662
3663            }
3664        }
3665
3666        if (is_iterable($otherReservations)) {
3667            foreach($otherReservations as $key => $val) {
3668                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3669                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($val), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3670                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($val));
3671
3672                // - do nothing - avoid conflict
3673                if (isset($reservedTz[$timeKeySlot])) {
3674                    continue;
3675                }
3676
3677                // - set reservation info
3678                $teacherData = $allReservationsData[$reservedLessonTime] ?? [];
3679                $currentTeacherData = $allReservationsData[$reservedLessonTime] ?? [];
3680
3681                // - set reservation data
3682                $reservedDatas = [
3683                    'reserved' => $val,
3684                    'val' => [],
3685                    'reservation_event' => $teacherSlotEvent,
3686                    'teacherData' => $teacherData,
3687                    'currentTeacherData' => $currentTeacherData
3688                ];
3689
3690                // - set reserved TZ
3691                $reservedTz[$timeKeySlot] = $reservedDatas;
3692            }
3693        }
3694
3695        $coupon = false;
3696        $couponDateCanUse = date('Y-m-d');
3697        $ccPeriod = false;
3698        if (!is_null($hash16)) {
3699            $freeTicket = false;
3700            if(PaymentTable::checkIfPaidUser($userId, $hash16)) {
3701                $freeTicket = true;
3702            } elseif (PaymentTable::checkIfCardAuth($userId, $hash16)) {
3703                $freeTicket = true;
3704            }
3705
3706            if ($freeTicket) {
3707                // check if can use coupon for reservation
3708                $coupon = ClassRegistry::init('UserCoupon')->canUseCoupon($userId);
3709                // get last coupon date used
3710                $couponDateCanUse = ClassRegistry::init('UserCoupon')->getDateCouponCanUse($userId);
3711
3712                // check if coupon campaign period
3713                $ccPeriod = myTools::couponCampaignPeriod();
3714            }
3715        }
3716        for ($i=0; $i<=7; $i++) {
3717            $cTime = strtotime("+" . $i . " days", $this->displayTime);
3718            $canUseCoupon = false;
3719            if (
3720                $couponDateCanUse && $coupon && $ccPeriod && !$counselingFlg
3721                && strtotime(date('Y-m-d', $cTime)) >= strtotime($couponDateCanUse)
3722            ) {
3723                $canUseCoupon = true;
3724            }
3725            $resRange = (isset($reservedRange[date('Ymd', $cTime)]))?$reservedRange[date('Ymd', $cTime)][0].'~'.$reservedRange[date('Ymd', $cTime)][1]:'';
3726            $days[] = array(
3727                'Y' => date('Y', $cTime),
3728                'm' => date('m', $cTime),
3729                'd' => date('d', $cTime),
3730                'w' => $weekday[date("w", $cTime)],
3731                'reserve_range' => $resRange,
3732                'canUseCoupon' => $canUseCoupon
3733            );
3734        }
3735
3736        // NC-4546 - check phone verification auth
3737        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
3738            'conditions' => array(
3739                'user_id' => $this->Auth->User('id'),
3740                'status' => 0
3741            )
3742        ));
3743        $notCorporateLightTeachers = false;
3744        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id'] );
3745
3746        if ( isset($corporateType) && $corporateType == Configure::read("corporate_type.light") ) {
3747            $checkCorpLightTeacher = ClassRegistry::init('Teacher')->corporateLightTeacher($teacherId);
3748            if (!$checkCorpLightTeacher) {
3749                $notCorporateLightTeachers = true;
3750            }
3751        }
3752
3753
3754        $grc = $this->getReserveAndCancelled($teacherId);
3755        $isShowCancellationAlert = $grc['this_month_cancellation_rate'] >= Configure::read('alert_cancellation_rate') ? true : false;
3756
3757        $limitedPlanAvailable = false;
3758
3759        // if user is corporate limited check if limited plan reservation is ON
3760        if ($corporateType == Configure::read("corporate_type.limited")) {
3761            $this->TeacherRankCoin->openDBReplica();
3762            $teacherRankCoin = $this->TeacherRankCoin->find('first', array(
3763                'fields' => array('TeacherRankCoin.limited_plan_reservation'),
3764               'conditions' => array('TeacherRankCoin.id' => $teacher['Teacher']['rank_coin_id'])
3765            ));
3766            $this->TeacherRankCoin->closeDBReplica();
3767
3768            $teacherRankCoin = $teacherRankCoin ? $teacherRankCoin['TeacherRankCoin'] : false;
3769            $limitedPlanAvailable = $teacherRankCoin && $teacherRankCoin['limited_plan_reservation'];
3770        }
3771        
3772        $callan_unlimited_flg = 0;
3773
3774
3775        # NJ-19429: check if teacher is in campaign
3776        if(
3777            (isset($user['User']['callan_option']) && $user['User']['callan_option'])
3778            ||
3779            (isset($user['User']['native_option']) && $user['User']['native_option'])
3780        ) {
3781            // - check existing reservation
3782            $has_callan_option_reserved = $this->LessonSchedule->hasCallanOptionReserved($userId);
3783            
3784            if($has_callan_option_reserved == 0) {
3785                // - check teacher callan option
3786                $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherInfo['current_rank_id']);
3787                $callan_unlimited_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? 1 : 0;
3788            }
3789        }
3790        
3791        #NJ-18780:set to allow normal lite plan to reserve
3792        $normalLitePlanCanReserveFlg = true;
3793        $isNormalLitePlan = false;
3794        $notNormalLitePlanTeacher = false;
3795
3796        $lessonRequestSlot = array();
3797
3798        if($this->isStudySapuriTosUser) {
3799            $lessonRequestSlot = array();            
3800        } else if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3801            $lessonRequestSlot = array();
3802        } else {
3803            //-- lesson request schedule
3804
3805            // - NJ-46366: prefetch lesson request slot
3806            $prefetchStart = date("Y-m-d 00:00:00");
3807            $prefetchEnd = date("Y-m-d 23:59:59", strtotime("+7 day"));
3808
3809            $prefetchedUserReservationData = $this->LessonSchedule->getReservationData(
3810                ['startDate' => $prefetchStart, 
3811                'endDate' => $prefetchEnd], 
3812                $user['User']['id'],
3813                $userLanguage
3814            );
3815    
3816            $prefetchedUsersCancelledReservationData = $this->LessonScheduleCancel->hasSlotBeenCancelled([
3817                'user_id' => $user['User']['id'],
3818                'lesson_time' => [
3819                    'startDate' => $prefetchStart, 
3820                    'endDate' => $prefetchEnd
3821                ]
3822            ]);
3823            
3824            $lessonRequestSlot = $this->LessonSchedule->lessonRequestSlotDetail(array(
3825                'user_id' => $userId,
3826                'teacher_id' => $teacherId,
3827                'timeDiffSecond' => $this->timeDiffSecond,
3828                'user_language' => $this->localizeDir,
3829                'campaign' => $discountcampaignPeriod,
3830                'userReservationData' => $prefetchedUserReservationData,
3831                'cancelledReservationData' => $prefetchedUsersCancelledReservationData
3832            ));
3833
3834            //-override hide dates or closed slots fetch reservation data
3835            $hiddenReservedTz = [];
3836            $resData = $this->LessonSchedule->getHiddenReservation([
3837                'user_id' => $userId
3838            ]);
3839
3840            if ($resData) {
3841                foreach ($resData as $key => $row) {
3842                    $lessonReqquestSlotData = $this->LessonSchedule->getReservationData($key, $userId, $this->localizeDir);
3843                    if (!empty($lessonReqquestSlotData)) {
3844                        $lessonReqquestSlotData['icon_color'] = $this->LessonSchedule->getIconColor($lessonReqquestSlotData, $key);
3845                        $hiddenReservedTz[TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'))] = $lessonReqquestSlotData;
3846                    }
3847                }
3848            }
3849        }
3850
3851        $membershipStatusIndex = UserTable::getStudentMembershipStatus($this->Auth->User('id'));
3852        $CampaignEligible = $this->CampaignInstructor->verifyStudentMembership($this->Auth->User('id'));
3853        $isNotNewCampaignEligible = !$CampaignEligible['verified'];
3854
3855        // NJ-33414
3856        $this->UsersDetail->openDBReplica();
3857        $fetchUsersDetail = $this->UsersDetail->find('first', array(
3858            'fields' => array(
3859                'user_id',
3860                'lesson_request_flg'
3861            ),
3862            'conditions' =>  array('user_id' => $userId),
3863            'recursive' => -1
3864        ));
3865        $this->UsersDetail->closeDBReplica();
3866        // - check if light plan and over ride to allow reserve on live lesson
3867        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans'))) {
3868            # not allow user to reserve live lesson
3869            $canLive = false;
3870        
3871            #set to normal lite plan user
3872            $isNormalLitePlan = true;
3873        
3874            #count the total upcoming reservation limited only to 1 reservation ?
3875            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
3876        
3877            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
3878                # not allow to reserve any more
3879                $normalLitePlanCanReserveFlg = false;
3880            }
3881
3882            // - check if teacher is callan half price
3883            if ($_isCallanHalfTeacher == 1 && empty($campaign)) {
3884                $notNormalLitePlanTeacher = true;
3885
3886                // - hide slots for lesson request 
3887                $lessonRequestSlot =  array();
3888            }
3889        }
3890
3891        //NJ-19429: teacher coin in slot restriction
3892        $teacherCoinDisableSlots = false;
3893        if($teacherCoin > 100){
3894            $isSlotReserveDisabled = in_array($membershipStatusIndex, Configure::read('slots_disabled_membership'));
3895            if($isSlotReserveDisabled){
3896                $lessonRequestSlot = array();
3897                $teacherCoinDisableSlots = true;
3898            }
3899        }
3900
3901        // NJ-47838 : check if live lesson callan discount campaign is enabled 
3902        $isLiveDiscountCallanCampaignCount = ClassRegistry::init('CampaignTagControl')->checkTeacherLiveCallanTag($discountcampaignPeriod['campaign_tag_id']);
3903        $excludeLessonRequestDiscount ??= '';
3904        $this->set(array(
3905            'smsThroughFlg' => isset($user['User']['sms_through_flg']) ? $user['User']['sms_through_flg'] : false,
3906            'verifyCount' => $verifyCount,
3907            'days' => $days,
3908            'times' => $times,
3909            'reserved' => $reserved,
3910            'user_id' => ($this->Auth->loggedIn()) ? $userId : null,
3911            'userCardCompany' => isset($user['User']['card_company']) ? $user['User']['card_company'] : 0,
3912            'timeDiff' => $timeDiff,
3913            'reservedTz' => $reservedTz,
3914            'limitedPlanAvailable' => $limitedPlanAvailable,
3915            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
3916            'notCorporateLightTeachers' => $notCorporateLightTeachers,
3917            'corporateLightUser' => ($corporateType == Configure::read("corporate_type.light")),
3918            'corporateLimitedUser' => ($corporateType == Configure::read("corporate_type.limited")),
3919            'teacherInfo' => $teacherInfo,
3920            'campaignPeriod' => $campaignPeriod,
3921            'discountCampaignPeriod' => $discountcampaignPeriod,
3922            'currentUserTime' => date(
3923                isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support")) ? 
3924                'd/m/Y G:i' : 'Y/m/d G:i', 
3925                $this->displayTime
3926            ),
3927            'currentUtcOffset' => $this->utcOffset,
3928            'isShowCancellationAlert' => $isShowCancellationAlert,
3929            'otherReservations' => $otherReservations,
3930            'viewSlotForSapuri' => $viewSlotForSapuri,
3931            'studySapuriId' => $this->studySapuriId,
3932            'lessonRequestSlot' => $lessonRequestSlot,
3933            'lessonRequestInvalidPlan' => in_array($membershipStatusIndex, [12, 13]),
3934            'teacherId' => $teacherId,
3935            'callanOption' => $callan_unlimited_flg,
3936            'user' => $user,
3937            'teacherData' => $teacherInfo,
3938            'weekday' => $weekday,
3939            'hiddenReservedTz' => $hiddenReservedTz,
3940            'canLive' => $canLive,
3941            'normalLitePlanCanReserveFlg' => $normalLitePlanCanReserveFlg,
3942            'isNormalLitePlan' => $isNormalLitePlan,
3943            'notNormalLitePlanTeacher' => $notNormalLitePlanTeacher,
3944            'teacherCoinDisableSlots' => $teacherCoinDisableSlots,
3945            'excludeLessonRequestDiscount'=> $excludeLessonRequestDiscount ? true : false,
3946            'lessonRequestFlg' => $fetchUsersDetail ? (int)$fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1,   // NJ-33414
3947            'notNewCampaignEligible' => $isNotNewCampaignEligible,
3948            'isLiveDiscountCallanCampaignCount' => $isLiveDiscountCallanCampaignCount
3949        ));
3950
3951        // get teacher information
3952        $teacher = new TeacherTable($teacherInfo);
3953        $teacherImageSrc = $teacher->getImageUrl();
3954        $teacherName = $teacher->getName();
3955        $this->set('teacherImageSrc', $teacherImageSrc);
3956        $this->set('teacherName', $teacherName);
3957
3958        $this->render('teacher_reserve_list_new');
3959
3960    }
3961
3962    //not used function
3963    public function updateChapterOptions() {
3964        $this->autoRender = false;
3965        $classId = $this->request->data['classid'];
3966        $teacherId = $this->request->data['teacherid'];
3967
3968        if (isset($this->request->data['firstid'])) {
3969            $firstId = $this->request->data['firstid'];
3970        } else {
3971            $firstId = '';
3972        }
3973
3974        if (isset($this->request->data['lastid'])) {
3975            $lastId = $this->request->data['lastid'];
3976        } else {
3977            $lastId = '';
3978        }
3979        return $this->result($teacherId, $classId, $firstId, $lastId);
3980    }
3981
3982    /**
3983     * @api {post} /user/waiting/result/:teacherId/:classId/:firstId/:lastId result()
3984     * @apiName result
3985     * @apiGroup Waiting
3986     * @apiDescription Retrieves the list of chapters for a specific class and teacher in Native Camp. It returns the updated list of chapters along with the first and last chapter IDs.
3987     *
3988     * @apiParam {String} teacherId The ID of the teacher.
3989     * @apiParam {String} classId The ID of the class.
3990     * @apiParam {String} [firstId] The ID of the first chapter.
3991     * @apiParam {String} [lastId] The ID of the last chapter.
3992     * 
3993     * @apiSuccess {Object[]} chapterList The list of chapters.
3994     * @apiSuccess {String} chapterList.UsersLastViewedTextbook.last_viewed_date The last viewed date of the chapter.
3995     * @apiSuccess {String} chapterList.LessonText.chapter_id The ID of the chapter.
3996     * @apiSuccess {String} chapterList.LessonText.chapter The name of the chapter.
3997     * @apiSuccess {String} firstChapter The ID of the first chapter.
3998     * @apiSuccess {String} lastChapter The ID of the last chapter.
3999     * @apiSuccess {String} teacherId The ID of the teacher.
4000     * @apiSuccess {String} classId The ID of the class.
4001     * @apiSuccess {Object} lastViewedTextInfo The information of the last viewed text.
4002     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.last_viewed_date The last viewed date of the text.
4003     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.class_id The ID of the class.
4004     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.chapter_id The ID of the chapter.
4005     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.preset Indicates if the text is preset.
4006     * @apiSuccess {String} userId The ID of the user.
4007     *
4008     * @apiSuccessExample {json} Success-Response:
4009     *     {
4010     *         "chapterList": [
4011     *             {
4012     *                 "UsersLastViewedTextbook": {
4013     *                     "last_viewed_date": "2023-12-01 10:00:00"
4014     *                 },
4015     *                 "LessonText": {
4016     *                     "chapter_id": "1",
4017     *                     "chapter": "Chapter 1"
4018     *                 }
4019     *             }
4020     *         ],
4021     *         "firstChapter": "1",
4022     *         "lastChapter": "10",
4023     *         "teacherId": "123",
4024     *         "classId": "456",
4025     *         "lastViewedTextInfo": {
4026     *             "UsersLastViewedTextbook": {
4027     *                 "last_viewed_date": "2023-12-01 10:00:00",
4028     *                 "class_id": "456",
4029     *                 "chapter_id": "1",
4030     *                 "preset": "0"
4031     *             }
4032     *         },
4033     *         "userId": "789"
4034     *     }
4035     *
4036     * @apiError {String} status The status of the request (NG).
4037     * @apiError {String} message The error message.
4038     *
4039     * @apiErrorExample {json} Error-Response:
4040     *     {
4041     *         "status": "NG",
4042     *         "message": "Invalid request."
4043     *     }
4044     * 
4045     * @apiSampleRequest off
4046     */
4047    public function result($teacherId, $classId, $firstId, $lastId) {
4048        $user_id = $this->Auth->user('id');
4049        if ($lastId != '') {
4050            $lastId = $this->request->data['lastid'];
4051            $classChapterList = $this->LessonText->find('all',
4052                array(
4053                    'joins' => array(
4054                        array(
4055                            'type'  => 'LEFT',
4056                            'table' => 'users_last_viewed_textbooks',
4057                            'alias' => 'UsersLastViewedTextbook',
4058                            'conditions' => array(
4059                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4060                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4061                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4062                                'UsersLastViewedTextbook.preset !=' => 1
4063                            )
4064                        )
4065                    ),
4066                    'fields' => array(
4067                        'UsersLastViewedTextbook.last_viewed_date',
4068                        'LessonText.chapter_id',
4069                        'LessonText.chapter'
4070                    ),
4071                    'conditions' => array(
4072                        'LessonText.class_id' => $classId,
4073                        'LessonText.chapter_id >' => $lastId,
4074                        'LessonText.status' => 1
4075                    ),
4076                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4077                )
4078            );
4079
4080        } else if ($firstId != '') {
4081            $firstId = $this->request->data['firstid'];
4082            $classChapterList = $this->LessonText->find('all',
4083                array(
4084                    'joins' => array(
4085                        array(
4086                            'type'  => 'LEFT',
4087                            'table' => 'users_last_viewed_textbooks',
4088                            'alias' => 'UsersLastViewedTextbook',
4089                            'conditions' => array(
4090                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4091                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4092                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4093                                'UsersLastViewedTextbook.preset !=' => 1
4094                            )
4095                        )
4096                    ),
4097                    'fields' => array(
4098                        'UsersLastViewedTextbook.last_viewed_date',
4099                        'LessonText.chapter_id',
4100                        'LessonText.chapter'
4101                    ),
4102                    'conditions' => array(
4103                        'LessonText.class_id' => $classId,
4104                        'LessonText.chapter_id <' => $firstId,
4105                        'LessonText.status' => 1
4106                    ),
4107                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4108                )
4109            );
4110        } else {
4111
4112            $classChapterList = $this->LessonText->find('all',
4113                array(
4114                    'joins' => array(
4115                        array(
4116                            'type'  => 'LEFT',
4117                            'table' => 'users_last_viewed_textbooks',
4118                            'alias' => 'UsersLastViewedTextbook',
4119                            'conditions' => array(
4120                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4121                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4122                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4123                                'UsersLastViewedTextbook.preset !=' => 1
4124                            )
4125                        )
4126                    ),
4127                    'fields' => array(
4128                        'UsersLastViewedTextbook.last_viewed_date',
4129                        'LessonText.class_id',
4130                        'LessonText.chapter_id',
4131                        'LessonText.chapter'
4132                    ),
4133                    'conditions' => array(
4134                        'LessonText.class_id' => $classId,
4135                        'LessonText.status' => 1
4136                    ),
4137                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4138                )
4139            );
4140        }
4141
4142        $classChapterFirstLast = $this->LessonText->find('first',
4143            array(
4144                'conditions' => array(
4145                    'LessonText.class_id' => $classId
4146                ),
4147                'fields' => array(
4148                    'MIN(LessonText.chapter_id) as first_chapter',
4149                    'MAX(LessonText.chapter_id) as last_chapter'
4150                )
4151            )
4152        );
4153
4154        if ($classChapterFirstLast) {
4155            $this->set('firstChapter', $classChapterFirstLast[0]['first_chapter']);
4156            $this->set('lastChapter', $classChapterFirstLast[0]['last_chapter']);
4157        } else {
4158            $this->set('firstChapter', '');
4159            $this->set('lastChapter', '');
4160        }
4161
4162        $this->set('teacherId', $teacherId);
4163        $this->set('classId', $classId);
4164        if ($firstId != '') {
4165            $classChapterList = array_reverse($classChapterList);
4166        }
4167
4168        //NC-634
4169        $lastViewedText = $this->UsersLastViewedTextbook->find(
4170            'all',
4171            array(
4172                'conditions' => array(
4173                    'UsersLastViewedTextbook.user_id' => $user_id,
4174                    'UsersLastViewedTextbook.preset !=' => 1
4175                ),
4176                'order' => array('UsersLastViewedTextbook.modified DESC'),
4177                'limit' => 1
4178            )
4179        );
4180
4181        $lastViewedTextInfo = array();
4182        if(isset($lastViewedText[0]) && isset($lastViewedText[0]['UsersLastViewedTextbook'])) {
4183            $lastViewedTextInfo = $lastViewedText[0];
4184        }
4185
4186        $this->set('lastViewedTextInfo', $lastViewedTextInfo);
4187        $this->set('chapterList', $classChapterList);
4188        $this->set('userId', $this->Auth->user('id'));
4189        $this->render('result', 'ajax');
4190    }
4191
4192    /**
4193     * @api {post} /user/waiting/loadMoreComments loadMoreComments()
4194     * @apiName loadMoreComments
4195     * @apiGroup Waiting
4196     * @apiDescription Loads more comments for a specific teacher or counselor in Native Camp. It returns the list of comments and indicates if there are more pages available.
4197     *
4198     * @apiBody {Number} page The page number to load.
4199     * @apiBody {String} teacherId The ID of the teacher.
4200     * @apiBody {Boolean} [isCounseling=false] Indicates if the request is for counseling comments.
4201     * @apiBody {Boolean} [isAvatar=false] Indicates if the request is for avatar comments.
4202     * @apiBody {Number} [order=0] The order of the comments.
4203     * 
4204     * @apiSuccess {Object[]} results The list of comments.
4205     * @apiSuccess {Number} results.id The ID of the comment.
4206     * @apiSuccess {String} results.star The HTML content for the star rating.
4207     * @apiSuccess {Number} results.age The age of the user who made the comment.
4208     * @apiSuccess {String} results.gender The gender of the user who made the comment.
4209     * @apiSuccess {String} results.user_comment The comment text.
4210     * @apiSuccess {String} results.date The date of the comment.
4211     * @apiSuccess {Object} results.textbook The textbook information.
4212     * @apiSuccess {String} results.textbook.textUrl The URL of the textbook.
4213     * @apiSuccess {String} results.textbook.textbook_image The image URL of the textbook.
4214     * @apiSuccess {String} results.textbook.textbook_name_lv1 The level 1 name of the textbook.
4215     * @apiSuccess {String} results.textbook.textbook_name_lv2 The level 2 name of the textbook.
4216     * @apiSuccess {String} results.textbook.textbook_name_lv3 The level 3 name of the textbook.
4217     * @apiSuccess {Number} results.review_id The ID of the review.
4218     * @apiSuccess {Number} results.like_total The total number of likes for the comment.
4219     * @apiSuccess {Number} results.dislike_total The total number of dislikes for the comment.
4220     * @apiSuccess {Number} results.voted Indicates if the user has voted on the comment (0: No, 1: Yes).
4221     * @apiSuccess {Boolean} lastPage Indicates if there are no more pages of comments available.
4222     *
4223     * @apiSuccessExample {json} Success-Response:
4224     *     {
4225     *         "results": [
4226     *             {
4227     *                 "id": 1,
4228     *                 "star": "<div>Star Rating</div>",
4229     *                 "age": 25,
4230     *                 "gender": "Male",
4231     *                 "user_comment": "Great lesson!",
4232     *                 "date": "2023-12-01",
4233     *                 "textbook": {
4234     *                     "textUrl": "http://example.com/textbook",
4235     *                     "textbook_image": "http://example.com/image.jpg",
4236     *                     "textbook_name_lv1": "Level 1",
4237     *                     "textbook_name_lv2": "Level 2",
4238     *                     "textbook_name_lv3": "Level 3"
4239     *                 },
4240     *                 "review_id": 1,
4241     *                 "like_total": 10,
4242     *                 "dislike_total": 2,
4243     *                 "voted": 1
4244     *             }
4245     *         ],
4246     *         "lastPage": false
4247     *     }
4248     *
4249     * @apiError {String} status The status of the request (NG).
4250     * @apiError {String} message The error message.
4251     *
4252     * @apiErrorExample {json} Error-Response:
4253     *     {
4254     *         "status": "NG",
4255     *         "message": "Invalid request."
4256     *     }
4257     * 
4258     * @apiSampleRequest off
4259     */
4260    public function loadMoreComments() {
4261            $this->autoRender = false;
4262            $this->layout = false;
4263            $userId = $this->Auth->user('id');
4264            if ($this->request->is('ajax')) {
4265                $perPage = 4;
4266                $data = $this->request->data;
4267
4268                // - if ajax is from counseling
4269                if (isset($data['isCounseling']) && $data['isCounseling']) {
4270                    $data['teacherId'] = $this->Teacher->getCounselorId();
4271                }
4272
4273                $params = array(
4274                    'order' => isset($data['order']) ? $data['order'] : 0,
4275                    'limit' => $perPage,
4276                    'offset' => $data['page'] * $perPage,
4277                    'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4278                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4279                    'lang' => $this->localizeDir
4280                );
4281                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
4282                $options['language_id'] = $reviewLanguage[0];
4283                $options['not_language_ids'] = $reviewLanguage[1] ?? null;
4284                $options['isAvatar'] = ( isset($data['isAvatar']) ) ? 1 : 0 ;
4285                $commentCount = $this->UsersClassEvaluation->getCommentCount($data['teacherId'], $options);
4286
4287                if (isset($data['isAvatar'])) {
4288                    $avatarParams = array(
4289                        'order' => isset($data['order']) ? $data['order'] : 0,
4290                        'limit' => $perPage,
4291                        'offset' => $data['page'] * $perPage,
4292                        'user_id' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4293                        'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4294                        'selfReviewsFlg' => false,
4295                        'avatar_id' => isset($data['teacherId']) ? $data['teacherId'] : 0,
4296                        'lang' => $this->localizeDir
4297                    );
4298
4299                    myTools::initializeApiTunnel(array('AvatarTeacherController'));
4300                    $teachersReviews = new AvatarTeacherController();
4301                    $comments = $teachersReviews->getAllAvatarEvaluation($avatarParams);
4302                    //count avatar reviews
4303                    $commentCount = $teachersReviews->getCountAllEvaluation(array("avatar_id" => isset($data['teacherId']) ? $data['teacherId'] : 0, 'lang' => $this->localizeDir));
4304
4305                } elseif ( isset($data['isCounseling']) ) {
4306                    myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
4307                    $teachersReviews = new TeachersCounselorReviewsController();
4308                    $teachersReviews->params = $params;
4309                    $comments = $teachersReviews->getAllCounselEvaluation();
4310                // office teacher
4311                } else {
4312                    myTools::initializeApiTunnel(array('TeachersReviewsController'));
4313                    $teachersReviews = new TeachersReviewsController();
4314                    $params['conditions'] = array(
4315                        'UsersClassEvaluation.teacher_id' => $data['teacherId'],
4316                        'UsersClassEvaluation.approve_flag' => 1,
4317                        'UsersClassEvaluation.user_comment <>' => ''
4318                    );
4319                    $teachersReviews->params = $params;
4320                    $comments = $teachersReviews->getReviews();
4321                }
4322
4323
4324                // - if ajax is from counseling
4325                $view = new View($this, false);
4326                $ctr = 0;
4327                $results = [];
4328                foreach ($comments as $comment) {
4329                    $user = new UserTable($comment['User']);
4330                    $review = new UsersClassEvaluationTable($comment['UsersClassEvaluation']);
4331                    $results[$ctr] = array(
4332                        'id' => $review->id,
4333                        'star' => $view->element('rate', array('rate' => $review->rate)),
4334                        'age' => $user->getAge(),
4335                        'gender' => $user->getGenderComment(),
4336                        'user_comment' => $review->getUserComment(),
4337                        'date' => date('Y-m-d', strtotime($review->getCreatedDate($this->timeDiffSecond)))
4338                    );
4339
4340                    $textbook = $comment['SubTextBook'] ?? null;
4341                    if ($textbook) {
4342                        $notSapuriTextFlg = false;
4343                        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
4344                            $pathLocale = '/'. $this->localizeDir;
4345                        }
4346                        $curTextType = $textbook['textbook_category_type'];
4347                        $textDefaultUrl = $pathLocale."/textbook/page-detail/".$textbook['textbook_category_type_id']."/".$textbook['textbook_connect_id'];
4348                        if (isset($this->studySapuriId)) {
4349                            $notSapuriTextFlg = (isset($this->sapuriTextTypes) && $curTextType != $this->sapuriTextTypes) ? true : false;
4350                        }
4351
4352                        $textbook['textUrl'] = $notSapuriTextFlg ? "javascript:void(0)" : $textDefaultUrl;
4353                        $textbook['textbook_image'] = $textbook['textbook_image'] ?? 'no_image';
4354
4355                        if (empty($textbook['textbook_connect_id'])) {
4356                            $textbook['textUrl'] = 'javascript:void(0)';
4357                            $textbook['textbook_image'] = 'no_image';
4358                            $textbook['textbook_name_lv1'] = '';
4359                            $textbook['textbook_name_lv2'] = '';
4360                            $textbook['textbook_name_lv3'] = '';
4361                        }
4362                    }
4363                    $results[$ctr]['textbook'] = $textbook;
4364
4365                    if ($userId) {
4366                        $results[$ctr]['review_id']  = $review->id;
4367                        $results[$ctr]['like_total'] = $review->like_votes;
4368                        $results[$ctr]['dislike_total'] = $review->dislike_votes;
4369                        $results[$ctr]['voted'] = $comment['UsersReviewVote']['vote'] != '' ? (int)$comment['UsersReviewVote']['vote'] : 0;
4370                    }
4371
4372                    $ctr++;
4373                }
4374            }
4375            $lastPage = (intval($data['page'] * $perPage) + $perPage) >= $commentCount ? true : false;
4376            $this->output($results, $lastPage);
4377        }
4378
4379
4380    private function output($data, $lastPage, $result = 'ok') {
4381        $result = array(
4382                'data' => $data,
4383                'result' => $result,
4384                'lastPage' => $lastPage,
4385            );
4386        echo json_encode($result);
4387        return;
4388    }
4389
4390    /**
4391      * @api {get} /user/waiting/is-can-cancel isCanCancel()
4392      * @apiName isCanCancel
4393      * @apiGroup Waiting
4394      * @apiDescription Checks if the user can cancel a reservation in Native Camp. It returns the status of the cancellation eligibility.
4395      *
4396      * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
4397      * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
4398      * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
4399      * 
4400      * @apiSuccess {Boolean} canCancel Indicates whether the user can cancel the reservation.
4401      *
4402      * @apiSuccessExample {json} Success-Response:
4403      *     {
4404      *         "canCancel": true
4405      *     }
4406      *
4407      * @apiError {String} status The status of the request (NG).
4408      * @apiError {String} message The error message.
4409      *
4410      * @apiErrorExample {json} Error-Response:
4411      *     {
4412      *         "status": "NG",
4413      *         "message": "Invalid request."
4414      *     }
4415      * 
4416      * @apiSampleRequest off
4417      */
4418    public function isCanCancel() {
4419        $this->autoRender = false;
4420        $get = $this->request->query;
4421
4422        // NC-8336
4423        if (
4424            isset($get['userId']) &&
4425            (isset($get['fromCorporateManagement']) || isset($get['fromSapuriTos']))
4426        ) {
4427            // get user data
4428            $this->User->openDBReplica();
4429            $user = $this->User->find('first', [
4430                'conditions' => ['User.id' => $get['userId']],
4431                'recursive' => -1
4432            ]);
4433            $this->User->closeDBReplica();
4434            $user = $user ? $user['User'] : [];
4435        } else {
4436            $get['userId'] = $this->Auth->user('id');
4437            $user = $this->sharedUserData['User'];
4438        }
4439
4440        $get['nc_terminal_type'] = 1; // pc
4441        $get['timeDiffSecond'] = $this->timeDiffSecond;
4442        $get['localizeDir'] = $this->localizeDir;
4443        $get['user'] = $user;
4444
4445        // open tunnel
4446        myTools::initializeApiTunnel(['ReservationController']);
4447
4448        // initialize controller
4449        $rc = new ReservationController();
4450
4451        // set data
4452        $rc->params = $get;
4453
4454        // process
4455        return $rc->isCanCancel();
4456    }
4457
4458    /**
4459     * @api {get} /user/waiting/convertString convertString()
4460     * @apiName convertString
4461     * @apiGroup Waiting
4462     * @apiDescription Converts a given string by disabling HTML tags and returns the result along with an ID name.
4463     *
4464     * @apiBody {String} _string The string to be converted.
4465     * @apiBody {String} id_name The ID name to be returned.
4466     * 
4467     * @apiSuccess {Object} result The result object.
4468     * @apiSuccess {String} result.res The converted string with HTML tags disabled.
4469     * @apiSuccess {String} result.idName The ID name.
4470     *
4471     * @apiSuccessExample {json} Success-Response:
4472     *     {
4473     *         "res": "Converted string",
4474     *         "idName": "exampleId"
4475     *     }
4476     *
4477     * @apiError {String} status The status of the request (NG).
4478     * @apiError {String} message The error message.
4479     *
4480     * @apiErrorExample {json} Error-Response:
4481     *     {
4482     *         "status": "NG",
4483     *         "message": "Invalid request."
4484     *     }
4485     * 
4486     * @apiSampleRequest off
4487     */
4488    public function convertString() {
4489        $this->autoRender = false;
4490        $string = $this->request->query['_string'];
4491        $idName = $this->request->query['id_name'];
4492        return json_encode(array('res' => myTools::disableHTMLTags($string), 'idName' => $idName));
4493    }
4494
4495    //not used function
4496    public function getTextbookOption($flag = '') {
4497        $this->autoRender = false;
4498        $result = array();
4499        $textbook_type = 0;
4500        $lessonNowReservation = false;
4501        $textbook_category_type = 0;
4502        $lesson_text_id = 0;
4503
4504        $userId = $this->Auth->user('id');
4505        $teacherId = $this->request->data['teacher_id'];
4506
4507        // NJ-9489 : check if membership is allowed to display counselor information
4508        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4509        $hideCouselorFromMember = 0;
4510
4511        if (
4512            !$_userPaymentPlan ||
4513            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4514        ) {
4515              $hideCouselorFromMember = 1;
4516        }
4517
4518        $textbookOptionArr = array();
4519        $Textbook = new TextbookController;
4520
4521        # course variable
4522        $getCourseArr = array(
4523            'teacher_id' => $teacherId,
4524            'flag' => $flag,
4525            'user_id' => $userId
4526        );
4527
4528        $course = $this->LessonText->getCourse($getCourseArr);
4529
4530            # User last viewed text book
4531            $getLastArr = array(
4532                'user_id' => $userId,
4533                'type' => 'course',
4534                'teacher_id' => $teacherId,
4535                'flag' => $flag
4536            );
4537            $courseDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4538            $courseId = $courseDefault['courseId'] ?? null;
4539            $curriculumId = $courseDefault['curriculumId'] ?? null;
4540            $lessonTextId = $courseDefault['lessonTextId'] ?? null;
4541
4542        $textbookOptionArr['courseArr'] = $course;
4543        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4544
4545        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4546        $textbookOptionArr['courseCurriculumId'] = $curriculumId;
4547        $textbookOptionArr['courseCurriculumArr'] = $dataSetOption;
4548        $courseCurriculumSelected = $textbookOptionArr['courseCurriculumArr']['Curriculum'][$curriculumId] ?? null;
4549        $textbookOptionArr['courseCurriculumSelected'] = $courseCurriculumSelected['data'][$lessonTextId] ?? null;
4550        $textbookOptionArr['courseCurriculumSelected']['badge'] = isset($courseDefault['textbook_info']['Curriculum']['badge']) ? $courseDefault['textbook_info']['Curriculum']['badge'] : 0;
4551        # category variable
4552        $getCategoryArr = array(
4553            'teacher_id' => $teacherId,
4554            'flag' => $flag,
4555            'user_id' => $userId
4556        );
4557        $category = $this->LessonText->getCategory($getCategoryArr);
4558
4559            # User last viewed text book
4560            $getLastArr = array(
4561                'user_id' => $userId,
4562                'type' => 'category',
4563                'teacher_id' => $teacherId,
4564                'flag' => $flag
4565            );
4566            $categoryDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4567            $classId = $categoryDefault['classId'] ?? null;
4568            $categoryLessonTextId = $categoryDefault['lessonTextId'] ?? null;
4569
4570        $textbookOptionArr['categoryArr'] = $category;
4571        $textbookOptionArr['categorySelected'] = isset($textbookOptionArr['categoryArr'][$classId]) ? $textbookOptionArr['categoryArr'][$classId] : 0;
4572        $textbookArr = $this->LessonText->getTextBookCategory(($textbookOptionArr['categorySelected']['ClassMaster']['id'] ?? null),$userId, $flag);
4573        $textbookOptionArr['categoryClassArr'] = $textbookArr['data'] ?? [];
4574        $textbookOptionArr['categoryClassSelected'] = isset($textbookOptionArr['categoryClassArr'][$categoryLessonTextId]) ? $textbookOptionArr['categoryClassArr'][$categoryLessonTextId] : 0;
4575
4576        # ------ default user textbook in iframe
4577        $defaultTextbookType = 2;
4578        $getLastArr = array(
4579            'user_id' => $userId,
4580            'type' => 'all',
4581            'teacher_id' => $teacherId,
4582            'flag' => $flag
4583        );
4584        $lastBookType = $this->LessonText->getLastViewedBook( $getLastArr );
4585        $defaultTextbookType = $lastBookType['textbook_type'] ?? null;
4586
4587        # - since course is the first option shown
4588        if ( $defaultTextbookType ) {
4589            if ( $defaultTextbookType == 1 ) {
4590                # Course
4591                $defaulClassId = $textbookOptionArr['courseCurriculumSelected']['class_id'] ?? 0;
4592                $defaulChapterId = $textbookOptionArr['courseCurriculumSelected']['chapter_id'] ?? 0;
4593            } else {
4594                # Category
4595                $defaulClassId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['class_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] : 0;
4596                $defaulChapterId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] : 0;
4597            }
4598        } else {
4599            # if the user don't have lastviewed ( Category )
4600            $defaulClassId = $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] ?? null;
4601            $defaulChapterId = $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] ?? null;
4602        }
4603        //use textbook of the reserve schedule
4604        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?class_id={$defaulClassId}&chapter_id={$defaulChapterId}";
4605        $textbookOptionArr['textbook_type'] = $defaultTextbookType;
4606        $textbookOptionArr['hide_switch'] = false;
4607        # ---------------- iframe end
4608
4609        //set flag for hide counselor textbook
4610        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
4611
4612        $view = new View($this, false);
4613        $result['option'] = $view->element('modal_textbook_selection',array('optionArr' => $textbookOptionArr));
4614        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
4615        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
4616
4617        return json_encode($result);
4618    }
4619
4620    /**
4621     * @api {post} /user/waiting/getAllTextbookOption getAllTextbookOption()
4622     * @apiName getAllTextbookOption
4623     * @apiGroup Waiting
4624     * @apiDescription Retrieves all textbook options for the authenticated user in Native Camp. It returns various information about the available textbooks, including courses, series, and user preferences.
4625     *
4626     * @apiBody {String} [teacher_id] The ID of the teacher.
4627     * @apiBody {String} [flag=all] The environment flag (e.g., lesson_now, reservation).
4628     * @apiBody {String} [live_flag] The live flag.
4629     * @apiBody {String} [action] The action to perform (e.g., setNextTextbookChapter).
4630     * @apiBody {String} [localizeDir] The localization directory.
4631     * @apiBody {String} [connectId] The connect ID of the textbook.
4632     * @apiBody {String} [resFlag] The reservation flag.
4633     * @apiBody {String} [textbook_level] The textbook level.
4634     * @apiBody {Boolean} [favorite_textbook_only=0] Indicates if only favorite textbooks should be retrieved.
4635     * 
4636     * @apiSuccess {Object} result The result object.
4637     * @apiSuccess {String} result.option The HTML content for the textbook options.
4638     * @apiSuccess {Boolean} result.levelFiltered Indicates if the textbooks are filtered by level.
4639     * @apiSuccess {String} result.textbook_default The default textbook URL.
4640     * @apiSuccess {Number} result.textbook_type The type of the textbook (1: Course, 2: Series).
4641     * @apiSuccess {Boolean} result.reservation_flag Indicates if the textbook is for reservation.
4642     * @apiSuccess {Boolean} result.disable_button_flag Indicates if the button should be disabled.
4643     * @apiSuccess {Boolean} result.textbook_live_lesson_flg Indicates if the textbook is for live lessons.
4644     * @apiSuccess {Object} result.user_preset_textbook_data The user preset textbook data.
4645     * @apiSuccess {Number} result.user_preset_textbook_data.id The ID of the textbook category.
4646     * @apiSuccess {Number} result.user_preset_textbook_data.connect_id The connect ID of the textbook.
4647     * @apiSuccess {Number} result.user_preset_textbook_data.sub_cat_id The subcategory ID of the textbook.
4648     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_id The ID of the textbook.
4649     * @apiSuccess {Boolean} result.user_preset_textbook_data.display_flag Indicates if the textbook should be displayed.
4650     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_type The type of the textbook.
4651     * @apiSuccess {Boolean} result.userPresetDisplayFlg Indicates if the user preset display flag is set.
4652     *
4653     * @apiSuccessExample {json} Success-Response:
4654     *     {
4655     *         "option": "<div>Textbook Options</div>",
4656     *         "levelFiltered": false,
4657     *         "textbook_default": "/HtmlTextbook/index?connect_id=123&html_dir=dir&chapter_id=1&isFromModal=1",
4658     *         "textbook_type": 1,
4659     *         "reservation_flag": true,
4660     *         "disable_button_flag": 0,
4661     *         "textbook_live_lesson_flg": true,
4662     *         "user_preset_textbook_data": {
4663     *             "id": 1,
4664     *             "connect_id": 123,
4665     *             "sub_cat_id": 2,
4666     *             "textbook_id": 3,
4667     *             "display_flag": true,
4668     *             "textbook_type": 1
4669     *         },
4670     *         "userPresetDisplayFlg": true
4671     *     }
4672     *
4673     * @apiError {String} status The status of the request (NG).
4674     * @apiError {String} message The error message.
4675     *
4676     * @apiErrorExample {json} Error-Response:
4677     *     {
4678     *         "status": "NG",
4679     *         "message": "Invalid request."
4680     *     }
4681     * 
4682     * @apiSampleRequest off
4683     */
4684    public function getAllTextbookOption() {
4685        // increase time limit
4686        set_time_limit(60);
4687        // increase max execution time
4688        ini_set('max_execution_time', 60);
4689        // inscrease memory limit
4690        myTools::alterPHPMemoryLimit('512M');
4691        $this->autoRender = false;
4692        $result = array();
4693        $textbook_category_type = 0;
4694        $lesson_text_id = 0;
4695        //set user id
4696        $userId = $this->Auth->user('id') ?? false;
4697        $param = array('user_id' => $userId);
4698        $textbookOptionArr = array();
4699        $teacherId = isset($this->request->data['teacher_id'])? $this->request->data['teacher_id'] : null;
4700        $envFlag = isset($this->request->data['flag'])? $this->request->data['flag'] : 'all';
4701        $liveFlag = isset($this->request->data['live_flag']) ? $this->request->data['live_flag'] : null;
4702        $connectIdCourse = $connectIdSeries = null;
4703        $action = (isset($this->request->data['action']) && $this->request->data['action'] == 'setNextTextbookChapter') ? $this->request->data['action'] : null;
4704        $isCourse = false;
4705        $teacherBadgeTextbooks     = array();
4706        $counselorTeacher = 0;
4707        $studentFinishedCallanLevelCheck = ClassRegistry::init('User')->hasFinishedCallanLevelCheck(array(
4708            'user_id' => $userId,
4709            'removeRelatedData' => true
4710        ));
4711
4712        // - if has localize directory
4713        if (isset($this->request->data['localizeDir']) && mb_strlen($this->request->data['localizeDir'])) {
4714            $this->localizeDir = $this->request->data['localizeDir'];
4715        }        
4716
4717        // NJ-5836
4718        // set params
4719        $displayRestrictionParams = array(
4720            'lang' => $this->localizeDir
4721        );
4722
4723        // get display restriction setting
4724        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
4725        
4726        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
4727        $userValidForSSBEDT = $this->userValidForSSBEDT();
4728
4729        //NC-8911: check user if for global course
4730        $isUserForGlobalCourse = false;
4731        if(isset($this->localizeDir) && $this->localizeDir !== Configure::read('default.user_language')) {
4732            $isUserForGlobalCourse = true;
4733        }
4734
4735        // NJ-9489 : check if membership is allowed to display counselor information
4736        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4737        $hideCouselorFromMember = 0;
4738
4739        if (
4740            !$_userPaymentPlan ||
4741            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4742        ) {
4743          $hideCouselorFromMember = 1;
4744        }
4745
4746        // check for counselor type teacher
4747        if ( $teacherId && $envFlag == "lesson_now" ) {
4748            $this->Teacher->openDBReplica();
4749            $counselorTeacher = $this->Teacher->find('count', array(
4750                'conditions' => array(
4751                    'Teacher.id' => $teacherId,
4752                    'Teacher.counseling_flg' => 1,
4753                    'Teacher.status' => 1
4754                ),
4755                'recursive' => -1
4756            ));
4757            $this->Teacher->closeDBReplica();
4758        }
4759        // filter textbook with teacher badge for dropwdown only : display all textbooks for Textbook page
4760        if ( $teacherId && !$counselorTeacher && $envFlag != "all" ) {
4761            $teacherBadgeTextbooks = ClassRegistry::init('TeacherBadge')->getTeacherBadge(array('teacher_id' => $teacherId, 'flag' => $envFlag));
4762        }
4763
4764        // check if student has reserved entry level
4765        $lessonScheduleModel = ClassRegistry::init('LessonSchedule');
4766        $lessonScheduleModel->clear();
4767        $hasReservedCallanLevelCheck = $lessonScheduleModel->hasReservedCallanLevelCheck(array('user_id' => $userId));
4768
4769        // Default Textbook
4770        $defaultParam = array(
4771            'env_flag' => $envFlag,
4772            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4773            'select_method' => "first",
4774            'teacher_id' => $teacherId,
4775            'user_id' => $userId,
4776            'load_description' => false,
4777            'userValidForSSBEDT' => $userValidForSSBEDT,
4778            'user_locale' => $this->localizeDir,
4779            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4780            'isCouncelor' => $counselorTeacher,
4781            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4782            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4783            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4784            'removeRelatedData' => true,
4785            'displayRestriction' => $displayRestriction,
4786            'fetch_favorite' => true
4787        );
4788
4789        if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId'])) {
4790            $defaultParam['connect_id'] = $this->request->data['connectId'];
4791        }
4792
4793        // - add additional parametes for global textbook
4794        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4795            $defaultParam['user_locale'] = $this->localizeDir;
4796        }
4797        $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4798        // if default textbook category is callan and student has yet to finish callan level check
4799        if (
4800            (isset($defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type']) && $defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type'] == 2)
4801            && (isset($defaultTextbookData['res_data']['Textbook']['callan_level_check']) && !$defaultTextbookData['res_data']['Textbook']['callan_level_check'])
4802            && !$studentFinishedCallanLevelCheck
4803        ) {
4804            $defaultParam['tb_default_levelcheck'] = true;
4805            $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4806
4807        // if not callan
4808        } else {
4809            //  NC-7592 - set next textbook chapter/series within the same category
4810            if ($action !== null && $action === 'setNextTextbookChapter') {
4811                $textbookDatails = isset($defaultTextbookData['res_data']) && isset($defaultTextbookData['res_data']['Textbook']) ? $defaultTextbookData['res_data']['Textbook'] : null;
4812                $textbookConnectDetails = $defaultTextbookData['res_data']['TextbookConnect'];
4813                $allTextbookParams = array(
4814                    'category_id' => $textbookConnectDetails['category_id'],
4815                    'connect_id' => $textbookConnectDetails['id'],
4816                    'subcategory_id' => $textbookConnectDetails['subcategory_id'],
4817                    'textbook_main_topic_id' => isset($textbookDatails['main_topic_id']) && $textbookDatails['main_topic_id'] ? $textbookDatails['main_topic_id'] : null,
4818                );
4819                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
4820                // if has next textbook chapter, preset
4821                if (
4822                    is_array($allTextbookChapters) && !is_null($allTextbookChapters)
4823                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
4824                ) {
4825                    $newPresetTextbookConnectId = $allTextbookChapters['next'];
4826                    $saveParams = array('userId' => $userId, 'connectId' => $newPresetTextbookConnectId);
4827                    $saveNextTextbookChapter = $this->saveTextbookPreset($saveParams);
4828                    // pull new default data
4829                    $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4830                }
4831            }
4832        }
4833        $defaultTextbook = $defaultTextbookData['res_data'];
4834        $defaultConnectId = $defaultTextbook['TextbookConnect']['id'];
4835        $defaultTextbookCategoryId = $defaultTextbook['TextbookCategory']['id'];
4836        // course
4837        if ($defaultTextbook['TextbookCategory']['type_id'] == 1) {
4838            $connectIdCourse = $defaultTextbook['TextbookConnect']['id'];
4839            $isCourse = true;
4840        }
4841        // series
4842        if ($defaultTextbook['TextbookCategory']['type_id'] == 2) {
4843            $connectIdSeries = $defaultTextbook['TextbookConnect']['id'];
4844        }
4845        // Get all Book
4846        $getAllBookArr = array(
4847            'env_flag' => $envFlag,
4848            'teacher_id' => $teacherId,
4849            'select_method' => 'all',
4850            'mode' => 'combine',
4851            'preset' => 'off',
4852            'user_id' => $userId,
4853            'load_description' => false,
4854            'userValidForSSBEDT' => $userValidForSSBEDT,
4855            'user_locale' => $this->localizeDir,
4856            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4857            'is_course' => $isCourse,
4858            'isCouncelor' => $counselorTeacher,
4859            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4860            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4861            'removeRelatedData' => true,
4862            'displayRestriction' => $displayRestriction,
4863            'ranked_textbook' => ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? false : true,
4864            'fetch_favorite' => true
4865        );
4866
4867        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
4868            $getAllBookArr['textbook_level'] = $this->request->data['textbook_level'];
4869        }
4870        
4871        // NC-7593 add favorites on textbook return
4872        if ($userId) {
4873            $params = array("user_id" => $userId);
4874            $textbookFavData = $this->UserTextbookFavorite->getUserFavoriteTextbooks($params);
4875            $getAllBookArr['textbookFavData'] = $textbookFavData;
4876        }
4877
4878        // - add additional parametes for global textbook
4879        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4880            $getAllBookArr['user_locale'] = $this->localizeDir;
4881        }
4882
4883        $allBookData = $this->Textbook->getTextbooks($getAllBookArr);
4884        $allBook = $allBookData['res_data'];
4885
4886        // course variable
4887        $course = $allBook['course'];
4888        $getCoursePresetArr = array(
4889            'env_flag' => 'all',
4890            'textbook_type' => 1,
4891            'select_method' => "first",
4892            'teacher_id' => $teacherId,
4893            'connect_id' => $connectIdCourse,
4894            'user_id' => $userId,
4895            'user_locale' => $this->localizeDir,
4896            'load_description' => false,
4897            'isCouncelor' => $counselorTeacher,
4898            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4899            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4900            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4901            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4902            'removeRelatedData' => true,
4903            'displayRestriction' => $displayRestriction,
4904            'fetch_favorite' => true
4905        );
4906        $coursePresetData = $this->Textbook->getTextbooks($getCoursePresetArr);
4907        $coursePreset = $coursePresetData['res_data'];
4908
4909        // User last viewed text book
4910        $courseId = $coursePreset['TextbookCategory']['id'];
4911        $courseSubCatId = $coursePreset['TextbookSubcategory']['id'];
4912        $courseSubCatBadge = isset($coursePreset['TextbookSubcategory']['badge']) && $coursePreset['TextbookSubcategory']['badge'] ? $coursePreset['TextbookSubcategory']['badge'] : null;
4913        $courseConnectId = $coursePreset['TextbookConnect']['id'];
4914        $courseLessonTextId = $coursePreset['Textbook']['id'];
4915
4916
4917        $textbookOptionArr['courseArr'] = $course;
4918        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4919
4920        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4921
4922        $textbookOptionArr['courseSubCatId'] = $courseSubCatId;
4923
4924        $textbookOptionArr['courseSubCatArr'] = $dataSetOption;
4925
4926        $courseSubCatSelected = $textbookOptionArr['courseSubCatArr']['TextbookSubcategory'][$courseSubCatId];
4927        $textbookOptionArr['courseSubCatSelected'] = $courseSubCatSelected['textbooks'][$courseConnectId];
4928        $textbookOptionArr['courseSubCatSelected']['index_position'] = isset($coursePreset['Textbook']['index_position']) && $coursePreset['Textbook']['index_position'] ? $coursePreset['Textbook']['index_position'] : null;
4929        $textbookOptionArr['courseSubCatSelected']['badge'] = $courseSubCatBadge;
4930
4931        // category variable
4932        $series = $allBook['series'];
4933        $getSeriesPresetArr = array(
4934            'env_flag' => 'all',
4935            'textbook_type' => 2,
4936            'select_method' => "first",
4937            'connect_id' => $connectIdSeries,
4938            'user_id' => $userId,
4939            'load_description' => false,
4940            'userValidForSSBEDT' => $userValidForSSBEDT,
4941            'user_locale' => $this->localizeDir,
4942            'isUserForGlobalCourse' => false,
4943            'isCouncelor' => $counselorTeacher,
4944            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4945            'removeRelatedData' => true,
4946            'displayRestriction' => $displayRestriction
4947        );
4948        $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
4949        $seriesPreset = $seriesPresetData['res_data'];
4950
4951        // User last viewed text book
4952        $seriesId = $seriesPreset['TextbookCategory']['id'];
4953        $seriesSubCatId = $seriesPreset['TextbookSubcategory']['id'];
4954        $seriesSubCatBadge = isset($seriesPreset['TextbookSubcategory']['badge']) ? $seriesPreset['TextbookSubcategory']['badge'] : null;
4955        $seriesConnectId = $seriesPreset['TextbookConnect']['id'];
4956
4957
4958        $textbookOptionArr['seriesArr'] = $series;
4959        $textbookOptionArr['seriesSpecialArr'] = $series;
4960        $textbookOptionArr['seriesSelected'] = isset($textbookOptionArr['seriesArr'][$seriesSubCatId]) ? $textbookOptionArr['seriesArr'][$seriesSubCatId] : 0;
4961
4962        $textbookOptionArr['seriesSubCatId'] = $seriesSubCatId;
4963        $textbookOptionArr['seriesSubCatSelected'] = $series[$seriesSubCatId];
4964        $textbookOptionArr['seriesTextbookArr'] = $series[$seriesSubCatId]['Textbook'];
4965        $textbookOptionArr['seriesTextbookSelected'] = $series[$seriesSubCatId]['Textbook'][$seriesConnectId];
4966        $textbookOptionArr['seriesTextbookSelected']['index_position'] = $seriesPreset['Textbook']['index_position'];
4967        $textbookOptionArr['seriesSubCatSelected']['badge'] = $seriesSubCatBadge;
4968
4969        $getSubcatParams = array(
4970            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4971            'teacher_id' => $teacherId,
4972            'category_id' => $defaultTextbookCategoryId,
4973            'env_flag' => $envFlag,
4974            'arrange_data' => "branch",
4975            'user_id' => $userId,
4976            'user_locale' => $this->localizeDir,
4977            'userValidForSSBEDT' => true,
4978            'isCouncelor' => $counselorTeacher,
4979            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4980            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4981            'removeRelatedData' => true,
4982            'fetch_favorite' => true
4983        );
4984        $getSubCategoryArr = $this->Textbook->getTextbooks($getSubcatParams);
4985
4986        // TextbookSubcategory
4987        if ( $defaultTextbook && ( isset( $getSubCategoryArr['res_data'] ) && $getSubCategoryArr['res_data'] ) ) {
4988            $subCategoryData = $getSubCategoryArr['res_data'];
4989            $subCategoryId = $defaultTextbook['TextbookSubcategory']['id'];
4990            $mainTopicTextbookId = isset($defaultTextbook['Textbook']['id']) && $defaultTextbook['Textbook']['id'] ? $defaultTextbook['Textbook']['id'] : null ;
4991            $textbookMainTopicId = isset($defaultTextbook['Textbook']['main_topic_id']) && $defaultTextbook['Textbook']['main_topic_id'] ? $defaultTextbook['Textbook']['main_topic_id'] : null ;
4992
4993            if ( $this->localizeDir != Configure::read('default.user_language') ) {
4994                $subCategoryName  = isset( $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ) && $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ? $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] : ( isset($defaultTextbook['TextbookSubcategory']['english_name']) && $defaultTextbook['TextbookSubcategory']['english_name'] ? $defaultTextbook['TextbookSubcategory']['english_name'] : $defaultTextbook['TextbookSubcategory']['name'] ) ;
4995            } else {
4996                $subCategoryName  = $defaultTextbook['TextbookSubcategory']['name'];
4997            }
4998
4999            // check for main topic overide subcategory name for daily news
5000            if ( $mainTopicTextbookId && $textbookMainTopicId ) {
5001                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
5002                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($mainTopicTextbookId,$langId);
5003                if ($textbookMainTopicName) { 
5004                    $subCategoryName = $textbookMainTopicName; 
5005                }
5006            }
5007
5008            $textbookOptionArr['subCategoryData'] = $subCategoryData;
5009            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5010            $textbookOptionArr['subCategoryName'] = $subCategoryName;
5011
5012            if ($envFlag == 'reservation') {
5013            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5014                $textbookOptionArr['selectedSubcatTeacherTotalTextbookBadge'] = (isset($subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'])) ? $subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'] : 0;
5015            }
5016        }
5017
5018        // check daily news category
5019        $dailyNewsCat = false;
5020        $dailyTopicsCat = false;
5021        $textbookObj = null;
5022        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_news_cat_id.series') ) {
5023            $dailyNewsCat = true;
5024            $textbookObj = $this->Textbook;
5025        }
5026        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_topics_textbook.category_id') ) {
5027            $dailyTopicsCat = true;
5028            $textbookObj = $this->Textbook;
5029        }
5030                $eikenEnable = ( $envFlag == 'lesson_now' && in_array($defaultTextbook['TextbookConnect']['category_id'], Configure::read('eiken_category_ids')));
5031        // Textbook chapters
5032
5033        // Course
5034        if ( $defaultTextbook['TextbookCategory']['type_id'] == 1 ) {
5035            $textbookChapterArr['textbooks'] = $courseSubCatSelected['textbooks'];
5036            $selectedTextbookArr = $textbookOptionArr['courseSubCatSelected'];
5037        }
5038        // Series
5039        if ( $defaultTextbook['TextbookCategory']['type_id'] == 2 ) {
5040            $textbookChapterArr['textbooks'] = $textbookOptionArr['seriesTextbookArr'];
5041            $selectedTextbookArr = $textbookOptionArr['seriesTextbookSelected'];
5042        }
5043
5044        $textbookOptionArr['dailyNewsCat'] = $dailyNewsCat;
5045        $textbookOptionArr['dailyTopicsCat'] = $dailyTopicsCat;
5046        $textbookOptionArr['textbookObj'] = $textbookObj;
5047        $textbookOptionArr['courseSubCatArr'] = $textbookChapterArr;
5048        $textbookOptionArr['courseSubCatSelected'] = $selectedTextbookArr;
5049        $textbookOptionArr['hasFinishedCallanEntry'] = $studentFinishedCallanLevelCheck;
5050        $textbookOptionArr['textbookCategoryType'] = $defaultTextbook['TextbookCategory']['textbook_category_type'];
5051        $textbookOptionArr['eikenEnable'] = $eikenEnable;
5052        $textbookOptionArr['favorite_textbook_only'] = isset($this->request->data['favorite_textbook_only']) ? $this->request->data['favorite_textbook_only'] : 0;
5053
5054        $defaultDir = $defaultTextbook['Textbook']['html_directory'];
5055        $defaultChapId = $defaultTextbook['Textbook']['chapter_id'];
5056        $defaultBagde = isset($defaultTextbook['TextbookSubcategory']['badge'])?$defaultTextbook['TextbookSubcategory']['badge']:null;
5057
5058        //use textbook of the reserve schedule
5059        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1";
5060        $textbookOptionArr['textbook_type'] = isset($defaultTextbook['TextbookCategory']['type_id'])? $defaultTextbook['TextbookCategory']['type_id'] : 0;
5061        $textbookOptionArr['hide_switch'] = ($textbook_category_type == 2);
5062        $textbookOptionArr['teacher_badge'] = $defaultBagde;
5063        $result['disable_button_flag'] = 0;
5064        # ---------------- iframe end
5065
5066        $view = new View($this, false);
5067
5068        //NJ-2601 : NJ-24096
5069        if ($envFlag == 'reservation') {
5070            $selectedDataTextbook = ($textbookOptionArr['textbook_type'] == 1) ? $textbookOptionArr['courseSelected'] : $textbookOptionArr['seriesSubCatSelected'];
5071            $textbookLiveLessonFlg = isset($selectedDataTextbook['TextbookCategory']['live_lesson_flg']) ? $selectedDataTextbook['TextbookCategory']['live_lesson_flg'] : false;
5072            if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId']) && $defaultTextbook['TextbookCategory']['display_flag']) {
5073                $result['user_preset_textbook_data']['id'] = $selectedDataTextbook['TextbookCategory']['id']; //cat id
5074                $result['user_preset_textbook_data']['connect_id'] = $selectedTextbookArr['connect_id'];
5075                $result['user_preset_textbook_data']['sub_cat_id'] = isset($selectedDataTextbook['TextbookSubcategory']['id']) ? $selectedDataTextbook['TextbookSubcategory']['id'] : 0;
5076                $result['user_preset_textbook_data']['textbook_id'] = isset($selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']) ? $selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id'] : 0;
5077                $result['user_preset_textbook_data']['display_flag'] = isset($courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']) ? $courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag'] : 0;
5078                $result['user_preset_textbook_data']['textbook_type'] = $textbookOptionArr['textbook_type'];
5079                $result['userPresetDisplayFlg'] = $textbookOptionArr['userPresetDisplayFlg'] = $defaultTextbook['TextbookCategory']['display_flag'];
5080            } else {
5081                $textbookOptionArr['textbook_type'] = 2;
5082                $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1&emptyReservationTextbook=1";
5083                $textbookOptionArr['has_reservation_connect_id'] = false;
5084                $result['disable_button_flag'] = 1;
5085            }
5086        }
5087
5088        $textbookOptionArr['all'] = ($envFlag == 'reservation') ? false : true;
5089
5090        // - check if live reservation
5091        if ( $teacherId && $liveFlag ) {
5092            $this->Teacher->openDBReplica();
5093            $liveReservation = $this->Teacher->find('count', array(
5094                'conditions' => array(
5095                    'Teacher.id' => $teacherId,
5096                    'Teacher.live_lesson_flg' => 1,
5097                    'Teacher.status' => 1
5098                ),
5099                'recursive' => -1
5100            ));
5101            $this->Teacher->closeDBReplica();
5102
5103            if ($liveReservation) {
5104                // - disabled textbooks if live_lesson_flg is OFF
5105                if (isset($textbookLiveLessonFlg) && !$textbookLiveLessonFlg) {
5106                    $result['textbook_live_lesson_flg'] = true;
5107                }
5108                $textbookOptionArr['live_reservation'] = true;
5109            }
5110        }
5111
5112
5113        // NJ-33115 prepare bookmark data of new callan textbook
5114        if ($userId) {
5115            $bookmarkSeriesData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[0]); // series bookmark
5116            $bookmarkCourseData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[1]); // course bookmark
5117            
5118            $bookmarkSeries = json_decode($bookmarkSeriesData, true);
5119            $bookmarkCourse = json_decode($bookmarkCourseData, true);
5120            if (isset($bookmarkSeries['bookmark_id']) && !empty($bookmarkSeries['bookmark_id'])) {
5121                $textbookOptionArr['bookmark']['series'] = $bookmarkSeries;
5122            }
5123            
5124            if (isset($bookmarkCourse['bookmark_id']) && !empty($bookmarkCourse['bookmark_id'])) {
5125                $textbookOptionArr['bookmark']['course'] = $bookmarkCourse;
5126            }
5127        }
5128
5129        //set flag for hide counselor textbook
5130        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
5131        $textbookOptionArr['favorites'] = isset($allBook['favorites']) ? $allBook['favorites'] : false;
5132        $textbookOptionArr['liveFlag'] = $liveFlag;
5133
5134        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
5135            $textbookOptionArr['textbook_level'] = $this->request->data['textbook_level'];
5136            $result['option'] = $view->element('textbook_category_selection',array(
5137                'courseArr' => isset($textbookOptionArr['courseArr']) ? $textbookOptionArr['courseArr'] : false,
5138                'seriesArr' => isset($textbookOptionArr['seriesArr']) ? $textbookOptionArr['seriesArr'] : false,
5139                'favorites' => isset($textbookOptionArr['favorites']) ? $textbookOptionArr['favorites'] : false,
5140                'liveFlag' => $liveFlag
5141            ));
5142            $result['levelFiltered'] = true;
5143        } else {
5144            $result['option'] = $view->element('modal_textbook_selection_2',array('optionArr' => $textbookOptionArr));
5145            $result['levelFiltered'] = false;
5146        }
5147        
5148        // - set result
5149        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
5150        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
5151        $result['reservation_flag'] = $defaultTextbook['TextbookCategory']['reservation_flg'];
5152        
5153        // - return json encoded data
5154        $this->response->type('json');
5155        $this->response->body(json_encode($result));
5156        return $this->response;
5157    }
5158
5159    /**
5160     * @api {post} /user/waiting/saveTexbook saveTextbookPreset()
5161     * @apiName saveTextbookPreset
5162     * @apiGroup Waiting
5163     * @apiDescription Saves the preset textbook for the authenticated user in Native Camp. It returns the status of the save operation and the details of the preset textbook.
5164     *
5165     * @apiBody {String} userId The ID of the user.
5166     * @apiBody {Object} presetParams The preset parameters.
5167     * @apiBody {Boolean} [is_pc_flg=true] Indicates if the request is from a PC.
5168     * @apiBody {String} [lang] The language code.
5169     * @apiBody {Boolean} [bypass_dummy_textbook_checker=true] Indicates if the dummy textbook checker should be bypassed.
5170     * 
5171     * @apiSuccess {Boolean} result Indicates whether the preset textbook was successfully saved.
5172     * @apiSuccess {String} image The image URL of the preset textbook.
5173     * @apiSuccess {String} name The name of the preset textbook.
5174     * @apiSuccess {String} cat_name The category name of the preset textbook.
5175     * @apiSuccess {String} chapter The chapter of the preset textbook.
5176     * @apiSuccess {Number} textbookCategoryTypeId The category type ID of the preset textbook.
5177     *
5178     * @apiSuccessExample {json} Success-Response:
5179     *     {
5180     *         "result": true,
5181     *         "image": "http://example.com/image.jpg",
5182     *         "name": "Textbook Name",
5183     *         "cat_name": "Category Name",
5184     *         "chapter": "Chapter 1",
5185     *         "textbookCategoryTypeId": 1
5186     *     }
5187     *
5188     * @apiError {String} status The status of the request (NG).
5189     * @apiError {String} message The error message.
5190     *
5191     * @apiErrorExample {json} Error-Response:
5192     *     {
5193     *         "status": "NG",
5194     *         "message": "Invalid request."
5195     *     }
5196     * 
5197     * @apiSampleRequest off
5198     */
5199    public function saveTextbookPreset($params = array()) {
5200        $status = false;
5201        $reservation_flg = 0;
5202        $this->autoRender = false;
5203
5204        // set preset params
5205        $presetParams = array(
5206            'is_pc_flg' => true,
5207            'lang' => $this->localizeDir,
5208            'bypass_dummy_textbook_checker'    => true
5209        );
5210
5211        if ($this->request->is('ajax')) {
5212            $data = $this->request->data;
5213
5214            // NJ-5836 set additional preset params
5215            $data['presetParams'] = $presetParams;
5216
5217            //if save succesful get the reservation flg of the textbook
5218            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5219                $status = true;
5220            }
5221
5222            // 8020
5223            $presetParams = array("user_id" => $data['userId']);
5224
5225            //add additional parameter in fetching preset textbook
5226            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5227                $presetParams["lang"] = $this->localizeDir;
5228            }
5229
5230            // check if user is valid for Study Sapuri Business English Daily textbooks
5231            if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5232                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5233              ){
5234                $presetParams['userValidForSSBEDT'] = true;
5235            }
5236
5237            //fetch preset
5238            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5239
5240        // request is POST
5241        } else {
5242            $data = $params;
5243
5244            // NJ-5836 set additional preset params
5245            $data['presetParams'] = $presetParams;
5246
5247            //if save succesful get the reservation flg of the textbook
5248            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5249                $status = true;
5250            }
5251
5252            // 8020
5253            $presetParams = array("user_id" => $data['userId']);
5254
5255            //add additional parameter in fetching preset textbook
5256            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5257                $presetParams["lang"] = $this->localizeDir;
5258            }
5259
5260            // check if user is valid for Study Sapuri Business English Daily textbooks
5261            if (
5262                (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5263                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5264            ){
5265                $presetParams['userValidForSSBEDT'] = true;
5266            }
5267
5268            //fetch preset
5269            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5270        }
5271        echo json_encode(array(
5272                'result' => $status,
5273                'image' => $textbookConnectId['image'],
5274                'name' => $textbookConnectId['name'],
5275                'cat_name' => $textbookConnectId['cat_name'],
5276                'chapter' => $textbookConnectId['chapter'],
5277                'textbookCategoryTypeId' => $textbookConnectId['textbook_info']['TextbookCategory']['type_id']
5278        ));
5279        exit;
5280    }
5281
5282    /**
5283     * @api {get} /user/:language/waiting/callLessonAlertandStartButton callLessonAlertandStartButton()
5284     * @apiName callLessonAlertandStartButton
5285     * @apiGroup Waiting
5286     * @apiDescription Retrieves the lesson alert and start button information for the authenticated user in Native Camp. It returns various information about the lesson status, user eligibility, and more.
5287     *
5288     * @apiParam {String} language The language code for the page.
5289     * 
5290     * @apiBody {String} studentId The ID of the student.
5291     * @apiBody {String} teacherId The ID of the teacher.
5292     * @apiBody {Boolean} counselingFlg Indicates if the lesson is a counseling session.
5293     * @apiBody {Boolean} [emergencyFlg=false] Indicates if the lesson is an emergency lesson.
5294     * @apiBody {Boolean} [isSpViewer=false] Indicates if the viewer is using a special viewer.
5295     * @apiBody {Boolean} [redLamp=false] Indicates if the red lamp is on.
5296     * 
5297     * @apiSuccess {Object} result The result object.
5298     * @apiSuccess {String} result.lesson_alert The HTML content for the lesson alert.
5299     * @apiSuccess {String} result.lesson_start_button The HTML content for the lesson start button.
5300     * @apiSuccess {Number} result.isReserved Indicates if the lesson is reserved (1: Yes, 0: No).
5301     * @apiSuccess {Number} result.unverifiedSMS Indicates if the SMS verification is unverified (1: Yes, 0: No).
5302     * @apiSuccess {Number} result.lessonStartIsNormalLitePLan Indicates if the user is on a normal lite plan (1: Yes, 0: No).
5303     * @apiSuccess {Number} result.studentDelayInSeconds The delay in seconds for the student lesson priority.
5304     *
5305     * @apiSuccessExample {json} Success-Response:
5306     *     {
5307     *         "lesson_alert": "<div>Lesson Alert Content</div>",
5308     *         "lesson_start_button": "<button>Start Lesson</button>",
5309     *         "isReserved": 1,
5310     *         "unverifiedSMS": 0,
5311     *         "lessonStartIsNormalLitePLan": 1,
5312     *         "studentDelayInSeconds": 3000
5313     *     }
5314     *
5315     * @apiError {String} status The status of the request (NG).
5316     * @apiError {String} message The error message.
5317     *
5318     * @apiErrorExample {json} Error-Response:
5319     *     {
5320     *         "status": "NG",
5321     *         "message": "Invalid request."
5322     *     }
5323     * 
5324     * @apiSampleRequest off
5325     */
5326    public function callLessonAlertandStartButton() {
5327        $this->autoRender = false;
5328        $view = new View($this, false);
5329        $get = $this->request->query;
5330        $lessonType = false;
5331        $displayFamilyAlert = false;
5332        $isSpViewer = !empty($get['isSpViewer']) ? 1: 0;
5333        $showTakeBusinessTestModal = false;
5334
5335        // check if teacher and student id exists
5336        if (
5337            !isset($get['studentId']) &&
5338            !isset($get['teacherId']) &&
5339            !isset($get['counselingFlg'])
5340        ) {
5341            throw new Exception("Invalid parameters!");
5342        }
5343
5344        // set vars
5345        $device = false;
5346        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
5347        $studentId = $get['studentId'];
5348        $teacherId = $get['teacherId'];
5349        $counselingFlg = $get['counselingFlg'];
5350        $isEmergencyLesson = (isset($get['emergencyFlg']) && $get['emergencyFlg']) ? true : false;
5351        $isGuestViwer = empty($studentId) ? 1 : 0;
5352        $isMobileView = $this->RequestHandler->isMobile();
5353
5354        $isRedLamp = isset($get['redLamp']) && $get['redLamp'] == "1" ? true : false;
5355        // get the data
5356        $teacherData = $this->Teacher->find('first', array(
5357            'fields' => array(
5358                'Teacher.home_flg',
5359                'Teacher.avatar_flg',
5360                'Teacher.avatar_parent_flg',
5361                'Teacher.avatar_id',
5362                'Teacher.native_speaker_flg',
5363            ),
5364            'conditions' => array(
5365                'Teacher.id' => $teacherId
5366            ),
5367            'recursive' => -1
5368        ));
5369
5370        // NJ-48797
5371        $isAvatarTeacher = isset($teacherData['Teacher']['avatar_flg']) && $teacherData['Teacher']['avatar_flg'] == 1;
5372
5373        if ($isAvatarTeacher) {
5374            $avatarParentFlg = isset($teacherData['Teacher']['avatar_parent_flg']) && $teacherData['Teacher']['avatar_parent_flg'] == 1;
5375        
5376            if (!$avatarParentFlg) {
5377                $getParentAvatarTeacher = $this->Teacher->find('first', array(
5378                    'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
5379                    'conditions' => array(
5380                        'Teacher.id' => $teacherData['Teacher']['avatar_id'],
5381                        'Teacher.avatar_parent_flg' => 1
5382                    ),
5383                    'recursive' => -1
5384                ));
5385            } else {
5386                $getParentAvatarTeacher = $teacherData;
5387            }
5388        }
5389
5390        $param = array(
5391            'homeFlag' => isset($teacherData['Teacher']['home_flg']) ? $teacherData['Teacher']['home_flg'] : null,
5392            'isGuestViwer' => $isGuestViwer
5393        );
5394
5395        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $param);
5396
5397        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : [];
5398        $hasRemainingLife = false;
5399
5400        if (
5401            $liveData &&
5402            $liveData['lesson_started'] &&
5403            !$liveData['lesson_finish'] &&
5404            !$isSpViewer &&
5405            !$isGuestViwer &&
5406            !$isMobileView
5407        ) {
5408
5409            // if api token is not set
5410            if (empty($this->sharedUserData['User']['api_token'])) {
5411
5412                $userApiToken = $this->User->generateAndSaveApiToken($studentId);
5413
5414                // update auth value
5415                $this->Session->write('Auth.User.api_token', $userApiToken);
5416            }
5417
5418            // open tunnel
5419            myTools::initializeApiTunnel(array('ChivoxTrainingController'));
5420
5421            // initialize controller
5422            $ctc = new ChivoxTrainingController();
5423
5424            // set data
5425            $ctc->params = [
5426                'nc_terminal_type' => 1, // pc
5427                'users_api_token' => $this->Auth->user('api_token'),
5428                'is_live_lesson' => 1,
5429                'chat_hash' => isset($liveData['chat_hash']) ? $liveData['chat_hash'] : null
5430            ];
5431
5432            // get remaining life details
5433            $noRemainingLifeDetails = json_decode($ctc->trainings_life_status(), true);
5434
5435            if (isset($noRemainingLifeDetails['error'])) {
5436                throw new Exception($noRemainingLifeDetails['error']['message']);
5437            }
5438
5439            $hasRemainingLife = ($noRemainingLifeDetails['infinite_life_flg'] || $noRemainingLifeDetails['remaining_life'] > 0 || $liveData['lesson_joined']) ? true : false;
5440        }
5441
5442        // check user agent
5443        if (strpos($ua, 'Silk') !== false) {
5444            $device = 'kindle';
5445        } else if (strpos($ua, 'Android') !== false) {
5446            $device = 'andriod';
5447        } else if (strpos($ua, 'iPhone') !== false) {
5448            $device = 'ios';
5449        } else if (strpos($ua, 'iPad') !== false) {
5450            $device = 'ios';
5451        } else if (strpos($ua, 'iPod') !== false) {
5452            $device = 'ios';
5453        } else {
5454            $device = 'pc';
5455        }
5456
5457        //check browser
5458        $unsupportedBorwser = false;
5459        $browser =  $this->request->header('User-Agent');
5460        if (preg_match('/(Edg|Edge)/i',$browser) ) {
5461            $unsupportedBorwser = false;
5462        } elseif (preg_match('/(OPR)/i',$browser)) {
5463            $unsupportedBorwser = true;
5464        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
5465            $unsupportedBorwser = false;
5466        } else if ( 
5467            $isSpViewer
5468            && preg_match('/(iPhone|iPad|iPod|Mozilla)/i',$browser)
5469            && preg_match('/(CriOS|FxiOS)/i',$browser)
5470        ) {
5471            //-- IOS CHROME
5472            $unsupportedBorwser = false;
5473        } else {
5474            $unsupportedBorwser = true;
5475        }
5476
5477        // get the teacher's current status
5478        $queryCondition = array(
5479            'fields' => array(
5480                    'TeacherRankCoin.coins',
5481                    'LessonOnair.id',
5482                    'LessonOnair.teacher_id',
5483                    'LessonOnair.user_id',
5484                    'LessonOnair.lesson_type',
5485                    'LessonOnair.live_lesson_flg'
5486                ),
5487            'joins' => array(
5488                array(
5489                    'type' => 'LEFT',
5490                    'table' => 'teacher_rank_coins',
5491                    'alias' => 'TeacherRankCoin',
5492                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
5493                )
5494            ),
5495            'conditions' => array(
5496                array('Teacher.id' => $teacherId)
5497            ),
5498            'show' => 'first'
5499        );
5500        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
5501
5502        if ($isEmergencyLesson && $this->isStudySapuriTosUser) {
5503            $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
5504            $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
5505            $queryCondition['fields'][] = "(
5506                ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
5507                ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
5508                ) as can_emergency_lesson";
5509            $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
5510                as student_no_next_reservation";
5511        }
5512
5513        $commonTeacherStatusParams = array(
5514            'page_display' => 'listTeacher',
5515            'query_conditions' => $queryCondition
5516        );
5517        $lessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
5518
5519        $teacherStatusStandByDurationFieldStr = '(CASE when TeacherStatus.status = 2 then (TIME_TO_SEC(TIMEDIFF(NOW(), TeacherStatus.created))) else 0 end) as teacher_status_standby_duration';
5520        // teacher_status if login or break
5521        $teacherStatus1 = $this->TeacherStatus->find('first', array(
5522            'fields' => array(
5523                'TeacherStatus.status',
5524                'TeacherStatus.remarks1',
5525                'TeacherStatus.remarks2',
5526                $teacherStatusStandByDurationFieldStr
5527            ),
5528            'conditions' => array('TeacherStatus.teacher_id' => $teacherId)
5529        ));
5530        
5531        $isNotAvatar = isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5532         $isNotCounselor = isset($lessonOnair['Teacher']['counseling_flg']) && $lessonOnair['Teacher']['counseling_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5533
5534        $studentRemainingSecondsDelay = 0;
5535        if( $isNotAvatar && $isNotCounselor ) {
5536            if( isset($teacherStatus1[0]['teacher_status_standby_duration']) && $teacherStatus1[0]['teacher_status_standby_duration'] ) {
5537                if( (int)$teacherStatus1[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
5538                    $studentRemainingSecondsDelay = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$teacherStatus1[0]['teacher_status_standby_duration'];
5539                }
5540            }
5541        }
5542
5543        // check if lessonOnair is empty
5544        if (isset($lessonOnair['LessonOnair'])) {
5545            $tmp = (object) $lessonOnair['LessonOnair'];
5546            if (!$tmp->id) {
5547                $lessonOnair['LessonOnair'] = null;
5548            }
5549        }
5550
5551        // pass onairs data
5552        $onair = $lessonOnair['LessonOnair'];
5553
5554        // check if lessonOnair contains empty values
5555        if (!empty($onair)) {
5556            $oOnair = new LessonOnairTable($onair);
5557        }
5558
5559        // set onair
5560        if (!empty($teacherStatus1) && empty($onair)) {
5561            $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
5562        }
5563
5564        // if teacher status is '4', disable lesson
5565        if (
5566            isset($teacherStatus1['TeacherStatus']['status']) &&
5567            isset($canLesson['lessonAvailable']) &&
5568            $teacherStatus1['TeacherStatus']['status'] == 4
5569        ) {
5570            $canLesson['lessonAvailable'] = 0;
5571        }
5572
5573        // normal
5574        $resEndTime1 = 25;
5575        $resEndTime2 = 55;
5576        if ( isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ) {
5577            $resEndTime1 = 19;
5578            $resEndTime2 = 49;
5579            // check if has upcoming reservation
5580            if (
5581                isset($canLesson['nextReservation']) &&
5582                $canLesson['nextReservation'] &&
5583                ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5584                isset($oOnair->status) &&
5585                isset($oOnair->connect_flg) &&
5586                $oOnair->connect_flg = 1
5587            ) {
5588                $canLesson['lessonAvailable'] = 0;
5589            }
5590
5591        }
5592
5593        // check if has upcoming reservation
5594        if (
5595            isset($canLesson['nextReservation']) &&
5596            $canLesson['nextReservation'] &&
5597            ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5598            isset($oOnair->status) &&
5599            isset($oOnair->connect_flg) &&
5600            $oOnair->connect_flg = 1
5601        ) {
5602            $oOnair->status = 2;
5603        }
5604
5605        //get preset textbook or last viewed
5606        $presetParams = array("user_id" => $get['studentId'], 'userValidForSSBEDT' => $this->userValidForSSBEDT());
5607
5608        //add additional parameter in fetching preset textbook
5609        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5610            $presetParams["lang"] = $this->localizeDir;
5611        }
5612
5613        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
5614        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
5615            # for preset
5616            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
5617            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5618
5619        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
5620            # use last viewed textbook if no preset data.
5621            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
5622            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5623        }
5624
5625        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
5626        $presetParams['is_pc_flg'] = 1;
5627
5628        # fetch preset
5629        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5630        if(!$preset) {
5631            unset($presetParams['connect_id']);
5632            unset($presetParams['last_opened_date']);
5633            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5634        }
5635
5636        $lessonData = $preset["textbook_info"];
5637        $categoryId = $lessonData["TextbookCategory"]["id"];
5638        $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
5639        $textbookId = $lessonData["Textbook"]["id"];
5640        if( $categoryTypeId == 1 ) { // course
5641            $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
5642        } else { // series
5643            $seriesId = $categoryId;
5644        }
5645
5646        // check teacher badge
5647        $checkBadge = $this->TeacherBadge->find("first", array(
5648                "conditions" => array(
5649                    "TeacherBadge.teacher_id" => $get['teacherId'],
5650                    "TeacherBadge.textbook_category_id" => $seriesId
5651                ),
5652                "fields" => array("TeacherBadge.id"),
5653                "recursive" => -1
5654            )
5655        );
5656
5657        $canLessonTextbook = false;
5658        if( $checkBadge || $counselingFlg) {
5659            $canLessonTextbook = true;
5660        }
5661
5662        //check if the preset textbook is doesn't have reserve_flg
5663        $textbookForReservationOnly = isset($preset['reservation_flg']) && !$counselingFlg ? $preset['reservation_flg'] : 0;
5664
5665        //get the textbook course / category
5666        $textbookCategoryName = isset($preset['name']) ? $preset['name'] : '' ;
5667
5668        //get next available schedule
5669        $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
5670        if(isset($canLesson['nextReserve'])) {
5671            $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
5672            $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
5673            $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
5674        }
5675
5676        //lesson type in lesson onair is reserved or there is a current reservation
5677        $this->LessonSchedule->recursive = 0;
5678        $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
5679        $isReserved = ((isset($lessonOnair['LessonOnair']['lesson_type']) && $lessonOnair['LessonOnair']['lesson_type'] == 2)
5680                                        || $reservedLessonData && ($reservedLessonData['Teacher']['id'] == $teacherId)) ? true : false;
5681        $corporateIndividualUser = false;
5682        $lessonOrangeButtonRemaining = false;
5683        $showNativeSpeakerWarning = false;
5684        if ($this->Auth->User('id')) {
5685            $userOnairData = $this->LessonOnair->find('first', array(
5686                'conditions' => array(
5687                    'LessonOnair.user_id' => $this->Auth->User('id'),
5688                    'LessonOnair.status' => Configure::read("lesson.status.lesson")
5689                )
5690            ));
5691
5692            $userDuplicateLesson = false;
5693            $lessonOnOther = false;
5694            $userNotEligible = false;
5695            $uOnair = isset($userOnairData['LessonOnair']) ? $userOnairData['LessonOnair']: '';
5696
5697            if ($uOnair != null) {
5698                $uOOnair = new LessonOnairTable($uOnair);
5699                //check user duplicate lesson
5700                if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
5701                    $userDuplicateLesson = true;
5702                    $lessonType = $uOOnair->lesson_type;
5703                }
5704                //check lesson on others
5705                if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
5706                    $lessonOnOther = true;
5707                }
5708            }
5709
5710            //NC-6310 check user have reservation
5711            $nextReservation = LessonScheduleTable::getReservation(array(
5712                'LessonSchedule.teacher_id' => $teacherId,
5713                'LessonSchedule.user_id' =>  $this->sharedUserData['User']['id']
5714            ));
5715
5716            //check user if free or failed
5717            $user = $this->sharedUserData;
5718            $userTable = new UserTable($user['User']);
5719            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
5720            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
5721            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
5722            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
5723            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
5724
5725            // if corporate user
5726            if (isset($user['User']['corporate_id'])) {
5727                $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
5728                $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
5729
5730                // NJ-3660: if 20th day onwards of the month, check if corporate user must take business test
5731                $corporateUserDate = time();
5732                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
5733                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
5734                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
5735
5736                // if user has not yet taken the monthly test and must flag is 1
5737                // and not a reserved lesson and current date is 20+ of the month
5738                $showTakeBusinessTestModal = false;
5739                if (
5740                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
5741                    !$isReserved &&
5742                    (
5743                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
5744                        (
5745                            $userAdminFlag == 1 ||
5746                            (
5747                                isset($user["User"]["nickname"]) &&
5748                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
5749                            )
5750                        )
5751                    )
5752                ) {
5753                    $showTakeBusinessTestModal = true;
5754                }
5755            }
5756
5757            // NC-5409 : Corporate Limited Plan
5758            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
5759            if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
5760
5761                // check if legible
5762                if (( ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) || (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5763                        $userDuplicateLesson || $unsupportedBorwser ||
5764                        $lessonOnOther
5765                ) && $studentId) {
5766                    $userNotEligible = true;
5767                }
5768
5769            } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
5770
5771                $corpLightCondition1 = (
5772                    ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
5773                    (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5774                    $userDuplicateLesson ||
5775                    $unsupportedBorwser ||
5776                    $lessonOnOther
5777                );
5778                // check if legible
5779                if ( $corpLightCondition1 && $studentId) {
5780                    $userNotEligible = true;
5781                }
5782            } elseif (
5783                (
5784                    isset($lessonOnair['Teacher']['native_speaker_flg']) &&
5785                    $lessonOnair['Teacher']['native_speaker_flg']
5786                ) &&
5787                (
5788                    $user['User']['native_option'] == null ||
5789                    $user['User']['native_option'] == 0
5790                ) &&
5791                !$isReserved &&
5792                !$tmp->live_lesson_flg &&
5793                !$this->isStudySapuriTosUser
5794            ) {
5795                $userNotEligible = true;
5796                $showNativeSpeakerWarning = true;
5797            } elseif ( // NJ-48797
5798                (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
5799                ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
5800                !$isReserved &&
5801                !$tmp->live_lesson_flg &&
5802                !$this->isStudySapuriTosUser
5803            ) {
5804                $showNativeSpeakerWarning = true;
5805                $userNotEligible = true;
5806            } else {
5807                // check if legible
5808                if (((!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5809                        $userDuplicateLesson || $unsupportedBorwser || (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
5810                        $lessonOnOther
5811                ) && $studentId) {
5812                    $userNotEligible = true;
5813                }
5814            }
5815            
5816            // show orange button
5817            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBorwser, $canLesson['lessonAvailable']);
5818
5819            # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
5820            $isReservedCanSuddenLesson = false;
5821            $isReservedCanLessonViewing = false;
5822            if (
5823                $canLessonTextbook &&             # - can lesson with the textbook
5824                !$textbookForReservationOnly && # - textbook not for reserve only
5825                !$unsupportedBorwser &&         # - supported browser
5826                $userDuplicateLesson &&         # - has lesson with other teacher
5827                $lessonType == Configure::read('lesson.type.reservation') &&
5828                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5829                !$this->isStudySapuriUser &&    # - not sapuri user
5830                ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
5831                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5832                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5833            ) {
5834                $isReservedCanSuddenLesson = true;
5835            }
5836
5837            if (
5838                !$this->isStudySapuriUser &&
5839                $lessonType == Configure::read('lesson.type.reservation') &&
5840                ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
5841            ) {
5842                $isReservedCanLessonViewing = true;
5843            }
5844            
5845            $canMidwayLesson = false;
5846            if (
5847                $canLessonTextbook &&             # - can lesson with the textbook
5848                !$textbookForReservationOnly && # - textbook not for reserve only
5849                !$unsupportedBorwser &&         # - supported browser
5850                $userDuplicateLesson &&         # - has lesson with other teacher
5851                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5852                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5853                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5854            ) {
5855                $canMidwayLesson = true;
5856            }
5857        }
5858
5859        // NC-3755
5860        if (
5861            isset($this->sharedUserData['User']['parent_id']) &&
5862            !is_null($this->sharedUserData['User']['parent_id'])
5863        ) {
5864            $parent = $this->User->find('first', array(
5865                'fields' => array(
5866                    'User.id',
5867                    'User.hash16',
5868                    'User.charge_flg'
5869                ),
5870                'conditions' => array(
5871                    'User.id' => $this->sharedUserData['User']['parent_id']
5872                ),
5873                'recursive' => -1
5874            ));
5875
5876            if ($parent && $parent['User']['charge_flg'] != 1) {
5877                $displayFamilyAlert = true;
5878            }
5879        }
5880        // NC-4544 - check phone verification auth
5881        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
5882            'conditions' => array(
5883                'user_id' => $this->Auth->User('id'),
5884                'status' => 0
5885            )
5886        ));
5887
5888
5889        $teacherParams = array(
5890            'type' => 'first',
5891            'args' => array(
5892                'conditions' => array(
5893                    'id' => $teacherId
5894                ),
5895                'recursive' => -1
5896            )
5897        );
5898        $teacherInfo = $this->Teacher->getTeachers($teacherParams);
5899
5900        // set localize url
5901        if (
5902            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
5903            $get['la'] != Configure::read('default.user_language')
5904        ) {
5905            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
5906        } else {
5907            $localizeUrl = myTools::getUrl();
5908        }
5909
5910        $corporateTypes = Configure::read('corporate_type_arr');
5911        // get live lesson coin
5912        $live_lesson_coin = 0;
5913        if (isset($teacherInfo['Teacher']['current_rank_id']) && $teacherInfo['Teacher']['current_rank_id']) {
5914             $live_lesson_coin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(array(
5915                 'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5916             ));
5917         }
5918
5919        # -don't check lesson daily limit if sapuri toS
5920        if (!$this->isStudySapuriTosUser) {
5921            // # NJ-3319
5922            $teacherStudentConnection = $this->TeacherStudentConnection->find('first', array(
5923                'conditions' => array(
5924                    'user_id' => $this->Auth->User('id'),
5925                    'teacher_id' => $teacherId
5926                ),
5927                'fields' => array(
5928                    'daily_lesson_minutes',
5929                    'daily_lesson_last_update',
5930                    'teacher_id'
5931                ),
5932                'recursive' => -1
5933            ));
5934
5935            $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
5936            if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
5937                $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
5938                    'teacher_id' => $teacherId,
5939                    'teacherStudentData' => $teacherStudentData,
5940                    'counseling_flg' => isset($lessonOnair['Teacher']['counseling_flg']) ? $lessonOnair['Teacher']['counseling_flg'] : 0,
5941                    'avatar_flg' => isset($lessonOnair['Teacher']['avatar_flg']) ? $lessonOnair['Teacher']['avatar_flg'] : 0,
5942                    'nickname' => $userTable->nickname,
5943                    'admin_flg' => $userTable->admin_flg,
5944                    'isReserved' => $isReserved,
5945                    'type' => 1
5946                ));
5947            }
5948        }
5949
5950        $resetTimeLocal = TimezoneTable::computeTimeToUser(array(
5951            'time' => strtotime(date("Y-m-d 00:00:00")),
5952            'timestamp' => $this->timeDiffSecond,
5953            'format' => 'H:i'
5954        ));
5955
5956        // NJ-51 : Set delay for student lesson priority group
5957        $studentLessonPriorityTimeDelay = 0;
5958        $studentDelayInSeconds = 0;
5959
5960        if( $isNotAvatar && $isNotCounselor ) {
5961            if( $oOnair && $oOnair->status == 1 && $oOnair->user_id == null ) {
5962                $studentLessonPriorityTimeDelay = $this->User->userPriorityDelay( array( 'user_id' => $this->Auth->user('id') ) );
5963                if( $studentLessonPriorityTimeDelay ){
5964                    $studentDelayInSeconds = (int) $studentLessonPriorityTimeDelay * 1000;
5965                }
5966            }
5967        }
5968
5969        $result['studentDelayInSeconds'] = $studentDelayInSeconds;
5970
5971        $hasOtherReserved = false;
5972        //- check if reservation is not by the current teacher
5973        if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
5974            $hasOtherReserved = true;
5975        }
5976
5977        $sapuriCoin = 0;
5978        if ($this->isStudySapuriUser) {
5979            $teacherParams = array(
5980                'teacher_id' => $teacherId,
5981                'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5982            );
5983            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
5984        }
5985
5986        # ~ check cannot emergency lesson
5987        $canEmergencyLesson = false;
5988        $emergencyBreakTime = ['status' => false];
5989        if (
5990            $isEmergencyLesson && 
5991            $this->isStudySapuriTosUser &&
5992            !$isReserved &&
5993            isset($lessonOnair[0]['can_emergency_lesson']) && 
5994            isset($lessonOnair[0]['student_no_next_reservation']) && 
5995            $lessonOnair[0]['can_emergency_lesson'] &&         # -can emergency
5996            $lessonOnair[0]['student_no_next_reservation']    # - no next reservation
5997        ) {
5998            $canEmergencyLesson = true;
5999        }
6000
6001        # ~if emergency lesson break time
6002        $currentMinutes = date("i");
6003        $currentHour = date("H");
6004        if ( $isEmergencyLesson && !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
6005            $canEmergencyLesson = false;
6006            $emergencyBreakTime['status'] = true;
6007            $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
6008            $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
6009        }
6010
6011        # ~no sudden lesson for sapuri toS user
6012        if ($this->isStudySapuriTosUser && !$isReserved) {
6013            $userNotEligible = true;
6014        }
6015
6016        $remainingLessonTime = 0;
6017        if( $isNotAvatar && $isNotCounselor && isset($oOnair->end_time)) {
6018            $remainingLessonTimeInSeconds = strtotime($oOnair->end_time)-strtotime('now');
6019            $remainingLessonTime = $remainingLessonTimeInSeconds <= 0 ? 0 : $remainingLessonTimeInSeconds;
6020        }
6021
6022    
6023        #NJ-18780: check for lite plan sudden lesson 
6024        // - check if reserved lesson
6025        $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
6026
6027        $isNormalLitePlanUser = (in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan') ) ) ? true : false;
6028
6029        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
6030
6031            # disable the lesson button for lite plan if it is not reserved lesson
6032            $userNotEligible = true;
6033
6034            # add if reserve is still ongoing 
6035            if ($isReserved) {
6036                $userNotEligible =false;
6037            }
6038        }
6039
6040        // NJ-29831: check if user has reserved lesson for the next 5 min
6041        $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
6042        $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
6043        $hasLessonBeforeActualTime = false;
6044        if (isset($scheduleReservationData) && !empty($scheduleReservationData) && !$onGoingLesson) {
6045            $hasLessonBeforeActualTime = $isReserved = true;
6046        }
6047
6048        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
6049        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($userTable->payment_plan_id);
6050
6051        $redirectPlanUrl = '';
6052        $use7DaysTrialModal = false;
6053        $baseUrl = myTools::getUrl($this->localizeDir);
6054
6055        // if failed settlement -> paid or corporate individual (standard/premium)
6056        if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
6057            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
6058        // if free 
6059        } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
6060            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
6061        // if free (trial not yet conducted)
6062        } elseif ($this->userMembershipType == 13) {
6063            $userNotEligible = true;
6064            $use7DaysTrialModal = true;
6065        // if corporate company settlement failed -> standard/premium or
6066        } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
6067            $redirectPlanUrl = $baseUrl . '/account/contract_information';
6068        }
6069
6070        $teacherLeaveNotice = '';
6071        $checkNextSchedule = isset($checkNextSchedule) ? $checkNextSchedule : false;
6072        $checkScheduleCurrent = isset($checkScheduleCurrent) ? $checkScheduleCurrent : false;
6073        $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
6074
6075        // NC-5554 : @modified. add trappings for meal break,
6076        // and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
6077        if (
6078            (($canLesson['lessonAvailable']
6079            && !$checkNextSchedule 
6080            && $checkScheduleCurrent)
6081            || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
6082            && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
6083            && !$isEmergencyLesson  # ~don't show in emergency page
6084            && !$this->isStudySapuriTosUser
6085            && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
6086            && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
6087        ) {
6088            $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
6089            $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
6090            $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
6091        }
6092
6093
6094        // NJ-56004 - if teacher is logged in and not on standby
6095        $isRedLamp = (isset($teacherStatus1['TeacherStatus']['status']) && $teacherStatus1['TeacherStatus']['status'] == 5) ? true : $isRedLamp;
6096
6097        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
6098        if (
6099            $isReserved && 
6100            (
6101                $this->isStudySapuriUser || 
6102                $this->isStudySapuriTosUser || 
6103                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
6104            )
6105        ) {
6106            $canDoLive = false;
6107        }
6108
6109
6110        // set view vars
6111        $data = array(
6112            'studentLessonPriorityTimeDelayInSeconds' => $studentLessonPriorityTimeDelay,
6113            'studentDelayInSeconds' => $studentDelayInSeconds,
6114            'studentRemainingSecondsDelay' => $studentRemainingSecondsDelay,
6115            'smsThroughFlg' => isset($userTable->sms_through_flg) ? $userTable->sms_through_flg : null,
6116            'verifyCount' => $verifyCount,
6117            'userFailFlag' => isset($userFailFlag)? $userFailFlag : 0,
6118            'userDoubleCheckFlag' => isset($userDoubleCheckFlag)? $userDoubleCheckFlag : 0,
6119            'userCardCompany' => isset($userCardCompany)? $userCardCompany : 0,
6120            'lessonOnOther' => isset($lessonOnOther)? $lessonOnOther : false,
6121            'unsupportedBorwser' => $unsupportedBorwser,
6122            'userDuplicateLesson' => isset($userDuplicateLesson)? $userDuplicateLesson : false,
6123            'lessonType' => $lessonType,
6124            'device' => $device,
6125            'canLesson' => $canLesson,
6126            'userId' => isset($studentId)? $studentId : '',
6127            'teacherId' => $teacherId,
6128            'teacherStatus' => $oOnair,
6129            'isRedLamp' => $isRedLamp,
6130            'statusCheck' => array(1, 4),
6131            'canLessonTextbook' => $canLessonTextbook,
6132            'isReserved' => $isReserved,
6133            'textbookForReservationOnly' => $textbookForReservationOnly,
6134            'textbookCategoryName' => $textbookCategoryName,
6135            'userNotEligible' => isset($userNotEligible)? $userNotEligible : false,
6136            'reservedLessonData' => $reservedLessonData,
6137            'corporateLimitedPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.limited') ) ,// corporate limited plan
6138            'corporateLightPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.light') ) ,// corporate light plan
6139            'corporateIndividualUser' => $corporateIndividualUser,
6140            'corporateUserFlg' => isset($corporateUserFlg) ? $corporateUserFlg : false,
6141            'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
6142            'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
6143            'checkNextSchedule' => $checkNextSchedule,
6144            'nextSchedule' => $nextSchedule,
6145            'checkScheduleCurrent' => $checkScheduleCurrent,
6146            'displayFamilyAlert' => $displayFamilyAlert,
6147            'nextReservation' => isset($nextReservation) ? $nextReservation : '',
6148            'lessonOnair' => $lessonOnair,
6149            'teacherInfo' => $teacherInfo,
6150            'localizeUrl' => $localizeUrl,
6151            'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
6152            'liveViewCoin' => $live_lesson_coin,
6153            'canDoLive' => $canDoLive,
6154            'points' => $this->UsersPoint->getCurrentUserPoint($userTable->id),
6155            'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
6156            'resetTimeLocal' => $resetTimeLocal == "00:00" ? "24:00" : $resetTimeLocal,
6157            'hasOtherReserved' => $hasOtherReserved,
6158            'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
6159            'isEmergencyLessonPage' => $isEmergencyLesson,
6160            'canEmergencyLesson' => $canEmergencyLesson,
6161            'emergencyBreakTime' => $emergencyBreakTime,
6162            'sapuriCoin' => $sapuriCoin,
6163            'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson ?? false,
6164            'isReservedCanLessonViewing' => $isReservedCanLessonViewing ?? false,
6165            'canMidwayLesson' => $canMidwayLesson ?? false,
6166            'remainingLessonTime' => $remainingLessonTime,
6167            'lessonEndTime' => isset($oOnair->end_time) ? $oOnair->end_time : '',
6168            'isGuestViwer' => $isGuestViwer,
6169            'isMobileView' => $isMobileView,
6170            'isSpViewer' => $isSpViewer,
6171            'lessonStartIsNormalLitePLan' => $isNormalLitePlanUser  ? 1 : 0,
6172            'dummyLessonRoom' => $hasLessonBeforeActualTime,
6173            'isCounselor' => (isset($teacherInfo['Teacher']['counseling_flg']) && $teacherInfo['Teacher']['counseling_flg']) ? true : false,
6174            'redirectPlanUrl' => $redirectPlanUrl,
6175            'use7DaysTrialModal' => $use7DaysTrialModal,
6176            'membershipType' => $this->userMembershipType,
6177            'teacherLeaveNotice' => $teacherLeaveNotice,
6178            'isStudySapuriTosUser' => $this->isStudySapuriUser,
6179            'hasRemainingLife' => $hasRemainingLife
6180        );
6181
6182        // load lesson alert
6183        $result['lesson_alert'] = $view->element('lesson_alert', $data);
6184
6185        // load lesson start button
6186        $result['lesson_start_button'] = $view->element('lesson_start_button', $data);
6187
6188        // reserved flag
6189        $result['isReserved'] = ($isReserved) ? 1 : 0;
6190        $result['unverifiedSMS'] = empty($verifyCount) && empty($userTable->sms_through_flg) ? 1 : 0;
6191
6192        //check if Lite User
6193        $result['lessonStartIsNormalLitePLan'] = $isNormalLitePlanUser ? 1 : 0;
6194
6195        // - set to json
6196        $this->response->type('json');
6197        $this->response->body(json_encode($result));
6198
6199        // return json data
6200        return $this->response;
6201    }
6202
6203    /**
6204     * @api {post} /user/waiting/loadMoreSelfReviews loadMoreSelfReviews()
6205     * @apiName loadMoreSelfReviews
6206     * @apiGroup Waiting
6207     * @apiDescription Loads more self-reviews for a specific teacher and user in Native Camp. It returns the list of self-reviews and indicates if there are more pages available.
6208     *
6209     * @apiBody {Number} [page=2] The page number to load (default is 2).
6210     * @apiBody {String} teacherId The ID of the teacher.
6211     * @apiBody {String} userId The ID of the user.
6212     * 
6213     * @apiSuccess {String} list The HTML list of self-reviews.
6214     * @apiSuccess {Boolean} hasNext Indicates whether there are more pages of self-reviews available.
6215     *
6216     * @apiSuccessExample {json} Success-Response:
6217     *     {
6218     *         "list": "<li>Review 1</li><li>Review 2</li>",
6219     *         "hasNext": true
6220     *     }
6221     *
6222     * @apiError {String} status The status of the request (NG).
6223     * @apiError {String} message The error message.
6224     *
6225     * @apiErrorExample {json} Error-Response:
6226     *     {
6227     *         "status": "NG",
6228     *         "message": "Invalid request."
6229     *     }
6230     * 
6231     * @apiSampleRequest off
6232     */
6233    public function loadMoreSelfReviews() {
6234        $this->autoRender = false;
6235        $list = '';
6236        if ($this->request->is('ajax')) {
6237            $page = isset($this->request->data['page']) ?  $this->request->data['page'] : 2;
6238          $teacherId = isset($this->request->data['teacherId']) ? $this->request->data['teacherId'] : 0;
6239          $userId = isset($this->request->data['userId']) ? $this->request->data['userId'] : 0;
6240            //reviews
6241      $selfReviews = $this->getUserReviews($userId, $teacherId, $page);
6242            $view = new View($this, false);
6243            $list = $view->element('self_comment_list', array('selfReviews' => $selfReviews));
6244        }
6245        return json_encode(
6246            array(
6247                'list' => $list,
6248                'hasNext' => $this->params['paging']['UsersClassEvaluation']['nextPage']
6249            ));
6250    }
6251
6252    /**
6253    * get own user review count and reviews
6254    * @param int user_id
6255    */
6256    private function getUserReviews($userId, $teacherId, $page = 1) {
6257        $this->paginate = array(
6258            'fields' => array(
6259                'UsersClassEvaluation.id',
6260                'UsersClassEvaluation.rate',
6261                'UsersClassEvaluation.user_comment',
6262                'UsersClassEvaluation.created'
6263            ),
6264            'conditions' => array(
6265                    'UsersClassEvaluation.teacher_id' => $teacherId,
6266                    'UsersClassEvaluation.user_id' => $userId,
6267                    'UsersClassEvaluation.rate IS NOT NULL',
6268                ),
6269            'page' => $page,
6270            'limit' => $this->selfReviewLimit,
6271            'order' => 'UsersClassEvaluation.created DESC',
6272            'recursive' => -1
6273        );
6274        return $this->paginate('UsersClassEvaluation');
6275    }
6276
6277    //Retrieves the reservation and cancellation statistics for a specific teacher in Native Camp. It returns the count of reservations and cancellations for the current and previous month, as well as the cancellation rates.
6278    public function getReserveAndCancelled($teacherId) {
6279        //params
6280        $param = array('teacher_id' => $teacherId);
6281
6282        //get count finish reservation and cancelled reservations
6283        $thisMonthReservation = $this->LessonSchedule->getCurrentMonthReservationCount($param);
6284        $lastMonthReservation = $this->LessonSchedule->getLastMonthReservationCount($param);
6285        $thisMonthReservedCancellation = $this->LessonScheduleCancel->getCurrentReservationCancelledCount($param);
6286        $lastMonthReservedCancellation = $this->LessonScheduleCancel->getLastReservationCancelledCount($param);
6287
6288        //get divisors
6289        $lastMonth = strtotime("first day of previous month");
6290        $thisMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId);
6291        $lastMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId, $lastMonth);
6292        $thisMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId);
6293        $lastMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId, $lastMonth);
6294
6295        $thisMonthDivisor = $thisMonthReservation + $thisMonthLSDivisor + $thisMonthLSCDivisor;
6296        $lastMonthDivisor = $lastMonthReservation + $lastMonthLSDivisor + $lastMonthLSCDivisor;
6297
6298        $thisMonthCancellationPercentage = ($thisMonthDivisor == 0) ? 0 : (int)(($thisMonthReservedCancellation / $thisMonthDivisor) * 100);
6299        $lastMonthCancellationPercentage = ($lastMonthDivisor == 0) ? 0 : (int)(($lastMonthReservedCancellation / $lastMonthDivisor) * 100);
6300
6301        return array(
6302            'this_month_reserved' => $thisMonthReservation,
6303            'last_month_reserved' => $lastMonthReservation,
6304            'this_month_cancelled' => $thisMonthReservedCancellation,
6305            'last_month_cancelled' => $lastMonthReservedCancellation,
6306            'this_month_cancellation_rate' => $thisMonthCancellationPercentage,
6307            'last_month_cancellation_rate' => $lastMonthCancellationPercentage
6308        );
6309    }
6310
6311    /**
6312    * shows the orange button after the lesson end
6313    * @param int $userId
6314    * @param int $teacherId
6315    * @param boolean $userNotEligible
6316    * @param boolean $unsupportedBorwser
6317    * @param boolean $canLesson
6318    * @return int $lessonOrangeButtonRemaining
6319    ***/
6320    private function triggerOrangeButton($userId='', $teacherId='', $userNotEligible=false, $unsupportedBorwser=false, $canLesson=false) {
6321        $lessonOrangeButtonRemaining = false;
6322        $secondsRemaining = $this->LessonOnairsLog->getLastLessonSecondsRemaining($userId, $teacherId);
6323        if ($secondsRemaining && !$userNotEligible && !$unsupportedBorwser && $canLesson) {
6324            $lessonOrangeButtonRemaining = $secondsRemaining;
6325        }
6326        return $lessonOrangeButtonRemaining;
6327    }
6328
6329    /**
6330     * @api {post} /user/waiting/deleteLessonOnair deleteLessonOnair()
6331     * @apiName deleteLessonOnair
6332     * @apiGroup Waiting
6333     * @apiDescription Deletes the ongoing lesson on-air information for the authenticated user in Native Camp. It forcefully terminates the lesson if necessary.
6334     *
6335     * @apiBody {Number} [lesson_finish=6] The lesson finish status (default is 6 for force terminate).
6336     * 
6337     * @apiSuccess {Boolean} result Indicates whether the lesson on-air information was successfully deleted.
6338     *
6339     * @apiSuccessExample {json} Success-Response:
6340     *     {
6341     *         "result": true
6342     *     }
6343     *
6344     * @apiError {String} status The status of the request (NG).
6345     * @apiError {String} message The error message.
6346     *
6347     * @apiErrorExample {json} Error-Response:
6348     *     {
6349     *         "status": "NG",
6350     *         "message": "Invalid request."
6351     *     }
6352     * 
6353     * @apiSampleRequest off
6354     */
6355    public function deleteLessonOnair () {
6356        $this->autoRender = false;
6357
6358        // get lesson onair
6359        $lessonOnair = $this->LessonOnair->find('first', array(
6360            'fields' => array(
6361                'LessonOnair.id',
6362                'LessonOnair.lesson_type',
6363                'LessonOnair.leave_lesson'
6364            ),
6365            'conditions' => array(
6366                'LessonOnair.user_id' => $this->Auth->user('id')
6367            ),
6368            'recursive' => -1
6369        ));
6370
6371        // if don't have ongoing lesson onair information
6372        if (!$lessonOnair) {
6373            $this->log("[delete_lesson_onair] has no lesson onair", "debug");
6374            return;
6375        }
6376
6377        // if reserve lesson
6378        if (
6379            !empty($lessonOnair) && // if has lesson onair
6380            $lessonOnair['LessonOnair']['lesson_type'] == 2 // if lesson type is reserve lesson
6381        ) {
6382            // if not yet leave lesson -> force to leave lesson
6383            if ($lessonOnair['LessonOnair']['leave_lesson'] == 0) {
6384                $force_leave_lesson = LessonOnairTable::studentForceLeaveLesson(['lesson_onair_id' => $lessonOnair['LessonOnair']['id']]);
6385                
6386                if (!$force_leave_lesson) {
6387                    throw new Exception('error: Unable to forcefully terminate ongoing lesson ->' . json_encode($lessonOnair));
6388                }
6389            }
6390            // if not normal lesson
6391        } elseif (isset($lessonOnair["LessonOnair"]["lesson_type"]) && $lessonOnair["LessonOnair"]["lesson_type"] != 1) {
6392            throw new Exception('error: not a normal lesson ->' . json_encode($lessonOnair));
6393        }
6394
6395        // log
6396        $this->log("[delete_lesson_onair] deleting lesson onair -> " . json_encode($lessonOnair), "debug");
6397        
6398        $lesson_finish_status = !empty($this->request->data['lesson_finish']) ? $this->request->data['lesson_finish'] : 6; // set lesson finish status, or else set to 6 = force terminate default
6399
6400        // delete lesson oanir
6401        $res = LessonOnairTable::delete($lessonOnair['LessonOnair']['id'], array(), $lesson_finish_status);
6402        
6403        return json_encode(array('result' => $res ? true : false));
6404    }
6405
6406    /**
6407    * get online teachers first page
6408    */
6409    private function getTeacherOnlineList() {
6410        $returnData = array();
6411        $conditionArr = array();
6412        $conditionResult = $this->getSearchCondition();
6413        $conditionResult['conditions'] = array($conditionResult['conditions']);
6414
6415        $commonTeacherStatusParams = array(
6416            'page_display' => 'searchPage',
6417            'query_conditions' => $conditionResult
6418        );
6419        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
6420        
6421        //clear teacher id
6422        $this->Session->delete('waiting-loadedTID');
6423        //save new teacher id
6424        if ($data) {
6425            $teacherId = array();
6426            foreach ($data['TeacherOnlineList'] as $teacher) {
6427                $teacherId[] = $teacher['Teacher']['id'];
6428            }
6429            $this->Session->write('waiting-loadedTID', $teacherId);
6430        }
6431        $returnData['teacherRecordCount'] = $data['teacherRecordCount'];
6432        $returnData['teacherData'] = $data['TeacherOnlineList'];
6433        $returnData['limitGauge'] = $conditionResult['limitGauge']+1;
6434        $returnData['limit'] = $conditionResult['limitCondition'];
6435        return $returnData;
6436    }
6437
6438    /**
6439    * get default search condition
6440    */
6441    private function getSearchCondition() {
6442        //default sort
6443        $sortCondition =  array(
6444            '(select if(count(*) > 0, 1, 0)
6445               FROM lesson_onairs
6446              WHERE teacher_id = Teacher.id AND status = 1 AND connect_flg = 1 LIMIT 1) desc',
6447
6448            '(if ((select if (count(*) > 0, 1, 0)
6449            from teacher_status
6450            where teacher_id = Teacher.id and status = 4 LIMIT 1)
6451
6452            OR
6453
6454            (select if (count(*) > 0, 1, 0)
6455            from lesson_onairs
6456            where teacher_id = Teacher.id and status <> 1 and connect_flg = 1 LIMIT 1), 3, 0)) desc',
6457
6458            'TeacherWeeklyRating.ratings desc',
6459
6460            'Teacher.lesson_count desc',
6461
6462            'Teacher.name asc'
6463        );
6464        //get block teachers id
6465        $blockList = BlockListTable::getBlocks($this->Auth->User('id'), false, 'all');
6466
6467        //default condition
6468        $conditions = array(
6469            'Teacher.id NOT IN' => $blockList,
6470            'Teacher.status' => 1,
6471            'Teacher.admin_flg' => 0,
6472            'Teacher.counseling_flg' => 0,
6473            'Teacher.last_login_time >=' => date('Y-m-d 00:00:00', strtotime('-59 days')),
6474            'LessonOnair.status = 1',
6475            'LessonOnair.connect_flg = 1'
6476        );
6477
6478        // NC-7031
6479        $conditions["AND"]["OR"] = array(
6480            array("Teacher.avatar_parent_flg" => 0, "Teacher.avatar_flg" => 0) // normal teacher
6481        );
6482        //stealth teacher
6483        if ($this->Cookie->read('stealth.setting') != 'on') {
6484            $conditions['Teacher.stealth_flg <>'] = 1;
6485        }
6486
6487        return array(
6488            'conditions' => $conditions,
6489            'sortCondition' => $sortCondition,
6490            'limitGauge' => 1,
6491            'pageLimit' => 80,
6492            'limitCondition' => 80,
6493            'defaultPageLimit' => 80,
6494            'seeMorePageLimit' => 18,
6495            'force_index' => 'FORCE INDEX(last_login_time)'
6496        );
6497    }
6498
6499    //not used function
6500    public function getApologyList($teacher_id = null) {
6501        $cancellesson = $this->LessonScheduleCancel->find('all', array(
6502            'conditions'=>array(
6503                'LessonScheduleCancel.user_id' => $this->Auth->user('id'),
6504                'LessonScheduleCancel.teacher_id' => $teacher_id,
6505#                'LessonScheduleCancel.lesson_time > ' => date('Y-m-d H:i:s'),
6506                'LessonScheduleCancel.status' => Configure::read('reserve_cancel_status_list'),//3 - admin cancel, 4 - system cancel, [24-28] - teacher cancellation, [29-33] - admin cancellation
6507                'LessonScheduleCancel.apology_show' => 1
6508            ),
6509            'fields' => array('LessonScheduleCancel.id', 'LessonScheduleCancel.lesson_time', 'LessonScheduleCancel.user_id','Teacher.id', 'Teacher.name'),
6510            'joins' => array(
6511                    array(
6512                        'type' => 'INNER',
6513                        'table' => 'teachers',
6514                        'alias' => 'Teacher',
6515                        'conditions' => array('Teacher.id = LessonScheduleCancel.teacher_id')
6516                        )
6517                ),
6518            'order' => 'LessonScheduleCancel.id desc'
6519        ));
6520
6521        return $cancellesson;
6522    }
6523
6524    /**
6525     * reservation limit
6526     * @return int
6527     * 1: warning 4th reservation
6528     * 2: 20 lesson reservation only
6529     * 3: 4 reservation only for each teacher
6530     * 4: cancellation limit
6531     * 5: complimentary plan
6532     * 6: corporate light max lesson limit
6533     * 7: lesson request max limit
6534     * 8: eligible for lesson request
6535     */ 
6536
6537     /**
6538     * @api {post} /user/waiting/limit-warning limitwarning()
6539     * @apiName limitwarning
6540     * @apiGroup Waiting
6541     * @apiDescription Checks for reservation limits and warnings for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
6542     *
6543     * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
6544     * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
6545     * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
6546     * 
6547     * @apiSuccess {String} status The status of the request (OK or NG).
6548     * @apiSuccess {Number} content The content of the response.
6549     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
6550     *
6551     * @apiSuccessExample {json} Success-Response:
6552     *     {
6553     *         "status": "OK",
6554     *         "content": 1,
6555     *         "cancelCount": 2
6556     *     }
6557     *
6558     * @apiError {String} status The status of the request (NG).
6559     * @apiError {Number} content The content of the response.
6560     * @apiError {Number} cancelCount The count of cancellations by the user.
6561     *
6562     * @apiErrorExample {json} Error-Response:
6563     *     {
6564     *         "status": "NG",
6565     *         "content": 0,
6566     *         "cancelCount": 0
6567     *     }
6568     * 
6569     * @apiSampleRequest off
6570     */
6571    public function limitwarning() {
6572        $this->autoRender = false;
6573
6574        if ($this->request->is('post')) {
6575            $post = $this->request->data;
6576
6577            // NC-8336
6578            if (
6579                isset($post['userId']) &&
6580                (isset($post['fromCorporateManagement']) || isset($post['fromSapuriTos']))
6581            ) {
6582                // nothing to do
6583            } else {
6584                $post['userId'] = $this->Auth->user('id');
6585                $post['user'] = $this->sharedUserData['User'];
6586            }
6587
6588            $post['nc_terminal_type'] = 1; // pc
6589            $post['timeDiffSecond'] = $this->timeDiffSecond;
6590 
6591            // open tunnel
6592            myTools::initializeApiTunnel(['ReservationController']);
6593
6594            // initialize controller
6595            $rc = new ReservationController();
6596
6597            // set data
6598            $rc->params = $post;
6599
6600            // process
6601            return $rc->limitWarning();
6602        } else {
6603            return json_encode([
6604                'status' => 'NG',
6605                'content' => 0,
6606                'cancelCount' => 0
6607            ]);
6608        }
6609    }
6610
6611    /**
6612     * @api {post} /user/waiting/updatedScheduleColor updatedScheduleColor()
6613     * @apiName updatedScheduleColor
6614     * @apiGroup Waiting
6615     * @apiDescription Retrieves the updated schedule color information for the authenticated user in Native Camp. It returns the dates when lessons are not available.
6616     *
6617     * @apiBody {String} teacherId The ID of the teacher.
6618     * 
6619     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6620     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6621     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6622     *
6623     * @apiSuccessExample {json} Success-Response:
6624     *     {
6625     *         "disableAll": false,
6626     *         "disabledDays": [
6627     *             "2023-12-01",
6628     *             "2023-12-02"
6629     *         ]
6630     *     }
6631     *
6632     * @apiError {String} status The status of the request (NG).
6633     * @apiError {String} message The error message.
6634     *
6635     * @apiErrorExample {json} Error-Response:
6636     *     {
6637     *         "status": "NG",
6638     *         "message": "Invalid request."
6639     *     }
6640     * 
6641     * @apiSampleRequest off
6642     */
6643    public function updatedScheduleColor() {
6644        $this->autoRender = false;
6645        if ($this->request->is('ajax')) {
6646            $teacherId = $this->request->data['teacherId'];
6647
6648            // NJ-18780 : 
6649            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6650            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
6651
6652            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6653                'userId' => $this->Auth->user('id'),
6654                'teacherId' => $teacherId,
6655                'timeDiff' => $this->timeDiff,
6656                'isNormalLitePlanUser' => $isNormalLitePlanUser
6657            ));
6658            return json_encode($disabledSchedule);
6659        }
6660    }
6661
6662    /**
6663     * @api {post} /user/waiting/getAvatarDisabledDates getAvatarDisabledDates()
6664     * @apiName getAvatarDisabledDates
6665     * @apiGroup Waiting
6666     * @apiDescription Retrieves the disabled dates for avatar lessons for the authenticated user in Native Camp. It returns the dates when avatar lessons are not available.
6667     *
6668     * @apiBody {String} teacherId The ID of the avatar teacher.
6669     * 
6670     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6671     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6672     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6673     *
6674     * @apiSuccessExample {json} Success-Response:
6675     *     {
6676     *         "disableAll": false,
6677     *         "disabledDays": [
6678     *             "2023-12-01",
6679     *             "2023-12-02"
6680     *         ]
6681     *     }
6682     *
6683     * @apiError {String} status The status of the request (NG).
6684     * @apiError {String} message The error message.
6685     *
6686     * @apiErrorExample {json} Error-Response:
6687     *     {
6688     *         "status": "NG",
6689     *         "message": "Invalid request."
6690     *     }
6691     * 
6692     * @apiSampleRequest off
6693     */
6694    public function getAvatarDisabledDates() {
6695        $this->autoRender = false;
6696        if ($this->request->is('ajax')) {
6697            $teacherId = $this->request->data['teacherId'];
6698            $getAvatarParams = array(
6699                "avatar_id" => $teacherId,
6700                "user_id" => $this->Auth->user('id'),
6701                "stealth_flg" => $this->Cookie->read('stealth.setting')
6702            );
6703
6704            // NJ-18780 : 
6705            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6706            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans'))) ? true : false;
6707
6708            $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
6709            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6710                'userId' => $this->Auth->user('id'),
6711                'teacherId' => $avatarTeacherIds,
6712                'timeDiff' => $this->timeDiff,
6713                'isNormalLitePlanUser' => $isNormalLitePlanUser
6714            ));
6715            return json_encode($disabledSchedule);
6716        }
6717    }
6718
6719    /**
6720     * @api {get} /user/sp/counselor_detail/ sp_counselor()
6721     * @apiName sp_counselor
6722     * @apiGroup Waiting
6723     * @apiDescription Redirects the user to the counselor detail page.
6724     *
6725     * @apiSuccess {String} url The URL to which the user is redirected.
6726     *
6727     * @apiSuccessExample {json} Success-Response:
6728     *     {
6729     *         "url": "https://example.com/user/counselor_detail"
6730     *     }
6731     *
6732     * @apiError {String} status The status of the request (NG).
6733     * @apiError {String} message The error message.
6734     *
6735     * @apiErrorExample {json} Error-Response:
6736     *     {
6737     *         "status": "NG",
6738     *         "message": "Invalid request."
6739     *     }
6740     * 
6741     * @apiSampleRequest off
6742     */
6743    public function sp_counselor() {
6744        return $this->redirect(myTools::getUrl() . '/user/counselor_detail', 301);
6745    }
6746
6747    /**
6748     * @api {get} /user/:language/counselor_detail counselor()
6749     * @apiName counselor
6750     * @apiGroup Waiting
6751     * @apiDescription Retrieves the counselor details for the authenticated user in Native Camp. It returns various information about the user's counselor status, lesson history, and more.
6752     *
6753     * @apiParam {String} language The language code for the page.
6754     * 
6755     * @apiSuccess {Object} teacher The counselor information.
6756     * @apiSuccess {String} teacher.id The ID of the counselor.
6757     * @apiSuccess {String} teacher.name The name of the counselor.
6758     * @apiSuccess {String} teacher.image_url The URL of the counselor's image.
6759     * @apiSuccess {Boolean} isFav Indicates whether the counselor is favorited by the user.
6760     * @apiSuccess {Object} teacherFavsColors The favorite colors for the counselor.
6761     * @apiSuccess {Number} favoriteCount The count of users who have favorited the counselor.
6762     * @apiSuccess {Boolean} isHide Indicates whether the counselor is hidden by the user.
6763     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
6764     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6765     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6766     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6767     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
6768     * @apiSuccess {String} userId The ID of the user.
6769     * @apiSuccess {Object} counselingTable The counseling table information.
6770     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
6771     * @apiSuccess {String} user_lang The native language of the user.
6772     * @apiSuccess {Object} userTimezoneData The user's timezone data.
6773     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
6774     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
6775     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
6776     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
6777     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
6778     * @apiSuccess {String} userCurrentTime The current time of the user.
6779     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
6780     * @apiSuccess {Boolean} canReport Indicates whether the user can report the counselor.
6781     * @apiSuccess {Object} keep_memo The memo kept by the user for the counselor.
6782     * @apiSuccess {String} keep_memo.id The ID of the memo.
6783     * @apiSuccess {String} keep_memo.memo The memo text.
6784     * @apiSuccess {Number} order The order of the reviews.
6785     * @apiSuccess {String} chatHash The chat hash for the lesson.
6786     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
6787     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
6788     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
6789     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
6790     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
6791     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
6792     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
6793     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
6794     * @apiSuccess {Object} user The user information.
6795     * @apiSuccess {String} user.id The ID of the user.
6796     * @apiSuccess {String} user.name The name of the user.
6797     * @apiSuccess {String} user.email The email of the user.
6798     *
6799     * @apiSuccessExample {json} Success-Response:
6800     *     HTTP/1.1 200 OK
6801     *     {
6802     *         "teacher": {
6803     *             "id": "123",
6804     *             "name": "Counselor Name",
6805     *             "image_url": "http://example.com/image.jpg"
6806     *         },
6807     *         "isFav": true,
6808     *         "teacherFavsColors": {...},
6809     *         "favoriteCount": 10,
6810     *         "isHide": false,
6811     *         "isLoggedIn": true,
6812     *         "disabledSchedule": {
6813     *             "disableAll": false,
6814     *             "disabledDays": [
6815     *                 "2023-12-01",
6816     *                 "2023-12-02"
6817     *             ]
6818     *         },
6819     *         "reviewsCount": 5,
6820     *         "userId": "123",
6821     *         "counselingTable": {...},
6822     *         "unsupportedBrowser": false,
6823     *         "user_lang": "en",
6824     *         "userTimezoneData": {
6825     *             "city_eng": "Tokyo",
6826     *             "utc_offset": "+09:00",
6827     *             "country_code_id": 81
6828     *         },
6829     *         "countryTimezone": "Japan",
6830     *         "counselorLampStatus": {...},
6831     *         "userCurrentTime": "2023/12/01 10:00",
6832     *         "login": true,
6833     *         "canReport": true,
6834     *         "keep_memo": {
6835     *             "id": "1",
6836     *             "memo": "This is a memo."
6837     *         },
6838     *         "order": 0,
6839     *         "chatHash": "example_chat_hash",
6840     *         "counselorLessonHistory": [
6841     *             {
6842     *                 "LessonOnairsLog": {
6843     *                     "start_time": "2023-12-01 10:00:00"
6844     *                 }
6845     *             }
6846     *         ],
6847     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
6848     *         "lessonHistoryCount": 5,
6849     *         "latestUserLesson": {
6850     *             "LessonOnairsLog": {
6851     *                 "start_time": "2023-12-01 10:00:00"
6852     *             }
6853     *         },
6854     *         "user": {
6855     *             "id": "123",
6856     *             "name": "John Doe",
6857     *             "email": "john.doe@test.com"
6858     *         }
6859     *     }
6860     *
6861     * @apiError {String} status The status of the request (NG).
6862     * @apiError {String} message The error message.
6863     *
6864     * @apiErrorExample {json} Error-Response:
6865     *     HTTP/1.1 400 Bad Request
6866     *     {
6867     *         "status": "NG",
6868     *         "message": "Invalid request."
6869     *     }
6870     * 
6871     * @apiSampleRequest off
6872     */
6873    public function counselor() {
6874        // NC-9875 start
6875        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi' || $this->localizeDir =='pt-br') {
6876            return $this->redirect(myTools::getUrl());
6877        }
6878
6879        $where = array(
6880            'user_id' => $this->Auth->user('id'),
6881            'teacher_id' => Configure::read('default_counselor_detail')
6882        );
6883
6884        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
6885            return $this->redirect('/mypage');
6886        }
6887
6888        // NC-6615 check if user can report the teacher
6889        $canReport = true;
6890        if (isset($this->sharedUserData['User'])) {
6891            $userData = new UserTable($this->sharedUserData['User']);
6892            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
6893            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
6894            $canReport = $userData->getMembershipTypeIndex();
6895            $membershipIndex = $canReport;
6896            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
6897
6898            //NJ-9489 - redirect to top page if payment type is not allowed
6899            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
6900
6901            // NJ-1454 - redirect to top page if membership type is not allowed
6902            if( !in_array($membershipIndex,$userMemberTypeCanDoCounselingArr) ) {
6903                return $this->redirect(myTools::getUrl());
6904            }
6905
6906            // NJ-9489 - redirect to top page if payment plan is not allowed
6907            if( 
6908                !$_userPaymentPlan ||
6909                in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
6910             ) {
6911                return $this->redirect(myTools::getUrl());
6912            }
6913        }
6914
6915        // NC-9875 end
6916        $counselor = $this->Teacher->getDefaultCounselorData();
6917        $this->set('teacher', $counselor);
6918
6919        //NJ-20069 counselor
6920        if(!$this->RequestHandler->isMobile()) {
6921            $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null);
6922            $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
6923            $lessonHistoryCount = count($lessonHistory['lessonHistory']);
6924            
6925            $formattedLatestLessonData = "";
6926            if(!empty($latestUserLesson))
6927            $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
6928            
6929            $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
6930            $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
6931            $this->set('lessonHistoryCount', $lessonHistoryCount);
6932            $this->set('latestUserLesson', $latestUserLesson);
6933        }
6934        
6935        //test
6936
6937
6938
6939        # favorite
6940        $where = array(
6941            'UsersFavorite.user_id'     => $this->Auth->user('id'),
6942            'UsersFavorite.teacher_id'     => Configure::read('default_counselor_detail')
6943        );
6944        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
6945        $this->set('isFav', $isFav);
6946        $favIds = $isFav ? [Configure::read('default_counselor_detail')] : [];
6947        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
6948        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
6949            'favIds' => $favIds,
6950            'favIdsTeacherCategory' => $teacherFavColor
6951        ]);
6952        $this->set('teacherFavsColors', $teacherFavsColors);
6953        # count favorite users
6954        $where = array(
6955            'UsersFavorite.teacher_id'  => Configure::read('default_counselor_detail')
6956        );
6957        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
6958        $this->set('favoriteCount', $favoriteCount);
6959
6960        # is teacher hide
6961        $where = array(
6962            'user_id' => $this->Auth->user('id'),
6963            'teacher_id' => Configure::read('default_counselor_detail')
6964        );
6965        $isHide = $this->BlockList->isTeacherHide($where);
6966        $this->set('isHide', $isHide);
6967
6968        //NC-7984 start
6969        $this->set('isLoggedIn', $this->Auth->loggedIn());
6970        $this->counselorLatestLessonHistory($this->Auth->user('id'));
6971        //NC-7984 end
6972
6973        $userId = $this->Auth->user('id');
6974        $counselingTable = $this->CounselingTable;
6975        // - get disabled dates
6976        $counselorIds = $this->Teacher->getCounselorId();
6977        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
6978            'userId' => $userId,
6979            'teacherId' => $counselorIds,
6980            'timeDiff' => $this->timeDiff
6981        ));
6982        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
6983        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
6984        $options['language_id'] = $reviewLanguage[0];
6985        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
6986        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
6987
6988        // - set data to view
6989        $setData = array(
6990            'reviewsCount' => $reviewsCount,
6991            'userId' => $userId,
6992            'disabledSchedule' => json_encode($disabledSchedule),
6993            'counselingTable' => $counselingTable
6994        );
6995        $unsupportedBrowser = false;
6996        $browser = $this->request->header('User-Agent');
6997
6998        if (preg_match('/(OPR|Opera)/i', $browser)) { 
6999            $unsupportedBrowser = true;
7000        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7001            $unsupportedBrowser = false;
7002        } else { 
7003            $unsupportedBrowser = true;
7004        }
7005
7006        $this->set('unsupportedBrowser', $unsupportedBrowser);
7007        $this->set($setData);
7008
7009        if (isset($this->sharedUserData['User'])) {
7010            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7011        }
7012
7013        # get user timezone
7014        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7015        $user_timezone_data = $this->Timezone->find('first',
7016            array(
7017                'fields' => array(
7018                    'Timezone.city_eng',
7019                    'Timezone.utc_offset',
7020                    'Timezone.country_code_id'
7021                ),
7022                'conditions' => array(
7023                    'Timezone.id' => $user_timezone_id
7024                ),
7025                'recursive' => -1
7026            )
7027        );
7028
7029        // - NJ-3653 get country
7030        $countryTimezone = null;
7031        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7032            // - Get all country Code
7033            $countryOptions = $this->Timezone->countryOptions();
7034
7035            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7036            $countryName = $countryOptions[$countryCodeId]['country_name'];
7037
7038            if (isset($countryName) && $countryName) {
7039                $countryTimezone = $countryName;
7040            }
7041        }
7042
7043        // NJ-20272:get counselor lamp status 
7044        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7045
7046        $this->set('countryTimezone', $countryTimezone);
7047        $this->set('userTimezoneData', $user_timezone_data);
7048        $this->set('counselorLampStatus',$counselorLampStatus);
7049
7050        #user time
7051        $datetime = date('Y-m-d H:i:s');
7052        $localTime = $this->displayTime;
7053        // NJ-29496
7054        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7055            $formattedDate = date('d/m/Y G:i', $localTime);
7056        } else {
7057            $formattedDate = date('Y/m/d G:i', $localTime);
7058        }
7059        $this->set('userCurrentTime', $formattedDate);    
7060        $this->set('login', $this->Auth->loggedIn());
7061        $this->set('canReport', $canReport);
7062
7063        $params = array(
7064            'this' => $this,
7065            'forceMobile' => false,
7066            'spView' => '/Mobile/Teacher/counselor_detail',
7067            'view' => '/Waiting/counselor_detail',
7068            'layout' => 'mobile',
7069            'mobile' => null,
7070            'pc' => null
7071        );
7072
7073        //NC-7603 get keep memo
7074        $this->UsersMemo->openDBReplica();
7075        $getKeepMemo = $this->UsersMemo->find('first', array(
7076            'fields' => array(
7077                'id',
7078                'memo'
7079            ),
7080            'conditions' => array(
7081                'user_id' => $this->Auth->user('id'),
7082                'is_counselor' => true
7083            ),
7084            'order' => array('id DESC'),
7085        ));
7086        $this->UsersMemo->closeDBReplica();
7087
7088        // - set keep memo
7089        $this->set('keep_memo', $getKeepMemo);
7090
7091        //set meta for teacher or counselor image 
7092        $counselorObject = new TeacherTable($counselor['Teacher']);
7093        $_teacherImgUrl = $counselorObject->getImageUrl();
7094
7095        //if has image 
7096        if ($_teacherImgUrl) {
7097
7098            //check if teacher has no image 
7099            if (empty($counselorObject->image_url) || !$counselorObject->image_url) {
7100                $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
7101                $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
7102            }
7103
7104            $this->set('meta_teacher_img',$_teacherImgUrl);        
7105        }
7106
7107        
7108        // - set review order
7109        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7110
7111        // class evaluation
7112        if ($this->request->query('chatHash')) {
7113            $chatHash = $this->request->query('chatHash');
7114
7115            // Check if chatHash is valid
7116            $this->LessonOnairsLog->openDBReplica();
7117            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7118            $this->LessonOnairsLog->closeDBReplica();
7119
7120            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7121                $this->LessonOnair->openDBReplica();
7122                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7123                $this->LessonOnair->closeDBReplica();
7124
7125                if(!$allData) {
7126                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7127                }
7128            }
7129
7130            if(!empty($this->sharedUserData['User'])){
7131                // - campaing stamps
7132                $this->getActiveCampaignStampData();
7133            }
7134
7135            $this->set('chatHash', $chatHash);
7136        }
7137        $this->set('counselor_teacher_detail', 1);
7138
7139        // - get user information
7140        $this->User->openDBReplica();
7141        $this->User->recursive = -1;
7142        $data = $this->User->findById($userId);
7143        $this->User->closeDBReplica();
7144
7145        $user = isset($data['User'])?$data['User']: null;
7146        $this->set('counselorObject', $counselorObject);
7147        $this->set('user', $user);
7148        myTools::render($params);
7149    }
7150
7151    /**
7152     * @api {get} /user/customersupport_detail customersupport()
7153     * @apiName customersupport
7154     * @apiGroup Waiting
7155     * @apiDescription Retrieves the customer support details for the authenticated user in Native Camp. It returns various information about the user's customer support status, lesson history, and more.
7156     * 
7157     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
7158     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
7159     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
7160     * @apiSuccess {String} userId The ID of the user.
7161     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7162     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7163     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7164     * @apiSuccess {Object} counselingTable The counseling table information.
7165     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
7166     * @apiSuccess {String} user_lang The native language of the user.
7167     * @apiSuccess {Object} userTimezoneData The user's timezone data.
7168     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
7169     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
7170     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
7171     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
7172     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
7173     * @apiSuccess {String} userCurrentTime The current time of the user.
7174     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
7175     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
7176     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
7177     * @apiSuccess {String} keep_memo.id The ID of the memo.
7178     * @apiSuccess {String} keep_memo.memo The memo text.
7179     * @apiSuccess {Number} order The order of the reviews.
7180     * @apiSuccess {String} chatHash The chat hash for the lesson.
7181     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
7182     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
7183     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
7184     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
7185     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
7186     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
7187     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
7188     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
7189     * @apiSuccess {Object} user The user information.
7190     * @apiSuccess {String} user.id The ID of the user.
7191     * @apiSuccess {String} user.name The name of the user.
7192     * @apiSuccess {String} user.email The email of the user.
7193     *
7194     * @apiSuccessExample {json} Success-Response:
7195     *     {
7196     *         "isHide": false,
7197     *         "isLoggedIn": true,
7198     *         "reviewsCount": 10,
7199     *         "userId": "123",
7200     *         "disabledSchedule": {
7201     *             "disableAll": false,
7202     *             "disabledDays": [
7203     *                 "2023-12-01",
7204     *                 "2023-12-02"
7205     *             ]
7206     *         },
7207     *         "counselingTable": {...},
7208     *         "unsupportedBrowser": false,
7209     *         "user_lang": "en",
7210     *         "userTimezoneData": {
7211     *             "city_eng": "Tokyo",
7212     *             "utc_offset": "+09:00",
7213     *             "country_code_id": 81
7214     *         },
7215     *         "countryTimezone": "Japan",
7216     *         "counselorLampStatus": {...},
7217     *         "userCurrentTime": "2023/12/01 10:00",
7218     *         "login": true,
7219     *         "canReport": true,
7220     *         "keep_memo": {
7221     *             "id": "1",
7222     *             "memo": "This is a memo."
7223     *         },
7224     *         "order": 0,
7225     *         "chatHash": "example_chat_hash",
7226     *         "counselorLessonHistory": [
7227     *             {
7228     *                 "LessonOnairsLog": {
7229     *                     "start_time": "2023-12-01 10:00:00"
7230     *                 }
7231     *             }
7232     *         ],
7233     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
7234     *         "lessonHistoryCount": 5,
7235     *         "latestUserLesson": {
7236     *             "LessonOnairsLog": {
7237     *                 "start_time": "2023-12-01 10:00:00"
7238     *             }
7239     *         },
7240     *         "user": {
7241     *             "id": "123",
7242     *             "name": "John Doe",
7243     *             "email": "john.doe@test.com"
7244     *         }
7245     *     }
7246     *
7247     * @apiError {String} status The status of the request (NG).
7248     * @apiError {String} message The error message.
7249     *
7250     * @apiErrorExample {json} Error-Response:
7251     *     {
7252     *         "status": "NG",
7253     *         "message": "Invalid request."
7254     *     }
7255     * 
7256     * @apiSampleRequest off
7257     */
7258    public function customersupport() {
7259
7260        // NC-9875 start
7261        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi') {
7262            return $this->redirect(myTools::getUrl());
7263        }
7264
7265        $isCustomerSupportUser = $this->UsersDetail->isCustomerSupportUser($this->Auth->user('id'));
7266        if(!$isCustomerSupportUser){
7267            return $this->redirect('/mypage');
7268        }
7269
7270        // NJ-54011: Check if user is Free trial not conducted yet.
7271        if ($this->userMembershipType == 13) {
7272            $this->set('membershipType', $this->userMembershipType);
7273        }
7274
7275        $where = array(
7276            'user_id' => $this->Auth->user('id'),
7277            'teacher_id' => Configure::read('default_counselor_detail')
7278        );
7279
7280        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
7281            return $this->redirect('/mypage');
7282        }
7283
7284        // NC-6615 check if user can report the teacher
7285        $canReport = true;
7286        if (isset($this->sharedUserData['User'])) {
7287            $userData = new UserTable($this->sharedUserData['User']);
7288            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
7289            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
7290            $canReport = $userData->getMembershipTypeIndex();
7291            $membershipIndex = $canReport;
7292            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
7293            //NJ-9489 - redirect to top page if payment type is not allowed
7294            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
7295        }
7296
7297        # is teacher hide
7298        $where = array(
7299            'user_id' => $this->Auth->user('id'),
7300            'teacher_id' => Configure::read('default_customer_support_detail')
7301        );
7302        $isHide = $this->BlockList->isTeacherHide($where);
7303        $this->set('isHide', $isHide);
7304
7305        $counselor = $this->Teacher->getDefaultCustomerSupportDetail();
7306
7307        //NC-7984 start
7308        $this->set('isLoggedIn', $this->Auth->loggedIn());
7309        $this->counselorLatestLessonHistory($this->Auth->user('id'));
7310        //NC-7984 end
7311
7312        $userId = $this->Auth->user('id');
7313        $counselingTable = $this->CounselingTable;
7314        // - get disabled dates
7315        $counselorIds = $this->Teacher->getCounselorId();
7316        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7317            'userId' => $userId,
7318            'teacherId' => $counselorIds,
7319            'timeDiff' => $this->timeDiff
7320        ));
7321        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
7322        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
7323        $options['language_id'] = $reviewLanguage[0];
7324        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
7325        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
7326
7327        // - set data to view
7328        $setData = array(
7329            'reviewsCount' => $reviewsCount,
7330            'userId' => $userId,
7331            'disabledSchedule' => json_encode($disabledSchedule),
7332            'counselingTable' => $counselingTable
7333        );
7334        $unsupportedBrowser = false;
7335        $browser =  $this->request->header('User-Agent');
7336
7337        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7338            $unsupportedBrowser = true;
7339        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7340            $unsupportedBrowser = false;
7341        } else { 
7342            $unsupportedBrowser = true;
7343        }
7344        $this->set('unsupportedBrowser', $unsupportedBrowser);
7345        $this->set($setData);
7346
7347        if (isset($this->sharedUserData['User'])) {
7348            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7349        }
7350
7351        # get user timezone
7352        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7353        $user_timezone_data = $this->Timezone->find('first',
7354            array(
7355                'fields' => array(
7356                    'Timezone.city_eng',
7357                    'Timezone.utc_offset',
7358                    'Timezone.country_code_id'
7359                ),
7360                'conditions' => array(
7361                    'Timezone.id' => $user_timezone_id
7362                ),
7363                'recursive' => -1
7364            )
7365        );
7366
7367        // - NJ-3653 get country
7368        $countryTimezone = null;
7369        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7370            // - Get all country Code
7371            $countryOptions = $this->Timezone->countryOptions();
7372
7373            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7374            $countryName = $countryOptions[$countryCodeId]['country_name'];
7375
7376            if (isset($countryName) && $countryName) {
7377                $countryTimezone = $countryName;
7378            }
7379        }
7380
7381        // NJ-20272:get counselor lamp status 
7382        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7383
7384        $this->set('countryTimezone', $countryTimezone);
7385        $this->set('userTimezoneData', $user_timezone_data);
7386        $this->set('counselorLampStatus',$counselorLampStatus);
7387
7388        #user time
7389        $datetime = date('Y-m-d H:i:s');
7390        $localTime = $this->displayTime;
7391        // NJ-29496
7392        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7393            $formattedDate = date('d/m/Y G:i', $localTime);
7394        } else {
7395            $formattedDate = date('Y/m/d G:i', $localTime);
7396        }
7397        $this->set('userCurrentTime', $formattedDate);    
7398        $this->set('login', $this->Auth->loggedIn());
7399        $this->set('canReport', $canReport);
7400
7401        $params = array(
7402            'this' => $this,
7403            'forceMobile' => false,
7404            'spView' => '/Mobile/Teacher/counselor_detail',
7405            'view' => '/Waiting/customersupport_detail',
7406            'layout' => 'mobile',
7407            'mobile' => null,
7408            'pc' => null
7409        );
7410
7411        //NC-7603 get keep memo
7412        $this->UsersMemo->openDBReplica();
7413        $getKeepMemo = $this->UsersMemo->find('first', array(
7414            'fields' => array(
7415                'id',
7416                'memo'
7417            ),
7418            'conditions' => array(
7419                'user_id' => $this->Auth->user('id'),
7420                'teacher_id' => Configure::read('default_customer_support_detail')
7421            ),
7422            'order' => array('id DESC'),
7423        ));
7424        $this->UsersMemo->closeDBReplica();
7425
7426        // - set keep memo
7427        $this->set('keep_memo', $getKeepMemo);
7428
7429        // - set review order
7430        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7431
7432        // class evaluation
7433        if ($this->request->query('chatHash')) {
7434            $chatHash = $this->request->query('chatHash');
7435
7436            // Check if chatHash is valid
7437            $this->LessonOnairsLog->openDBReplica();
7438            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7439            $this->LessonOnairsLog->closeDBReplica();
7440
7441            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7442                $this->LessonOnair->openDBReplica();
7443                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7444                $this->LessonOnair->closeDBReplica();
7445
7446                if(!$allData) {
7447                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7448                }
7449            }
7450
7451            if(!empty($this->sharedUserData['User'])){
7452                // - campaing stamps
7453                $this->getActiveCampaignStampData();
7454            }
7455
7456            $this->set('chatHash', $chatHash);
7457        }
7458
7459        $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null, true);
7460        $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
7461        $lessonHistoryCount = count($lessonHistory['lessonHistory']);
7462        $lessonHistoryCount = 0;
7463        
7464        $formattedLatestLessonData = "";
7465        if(!empty($latestUserLesson))
7466        $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
7467        
7468        $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
7469        $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
7470        $this->set('lessonHistoryCount', $lessonHistoryCount);
7471        $this->set('latestUserLesson', $latestUserLesson);
7472
7473        // - get user information
7474        $this->User->openDBReplica();
7475        $this->User->recursive = -1;
7476        $data = $this->User->findById($userId);
7477        $this->User->closeDBReplica();
7478
7479        $user = isset($data['User'])?$data['User']: null;
7480        $this->set('teacher', $counselor);
7481        $this->set('user', $user);
7482        $this->set('isCustomerSupportUser', true);
7483         myTools::render($params);
7484        
7485    }
7486
7487    //end of customer support func
7488
7489
7490
7491    /**
7492     * @api {post} /user/waiting/counselingGetDisabledDates counselingGetDisabledDates()
7493     * @apiName counselingGetDisabledDates
7494     * @apiGroup Waiting
7495     * @apiDescription Retrieves the disabled dates for counseling sessions for the authenticated user in Native Camp. It returns the dates when counseling sessions are not available.
7496     *
7497     * @apiBody {String} userId The ID of the user.
7498     * 
7499     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7500     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7501     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7502     *
7503     * @apiSuccessExample {json} Success-Response:
7504     *     {
7505     *         "disableAll": false,
7506     *         "disabledDays": [
7507     *             "2023-12-01",
7508     *             "2023-12-02"
7509     *         ]
7510     *     }
7511     *
7512     * @apiError {String} status The status of the request (NG).
7513     * @apiError {String} message The error message.
7514     *
7515     * @apiErrorExample {json} Error-Response:
7516     *     {
7517     *         "status": "NG",
7518     *         "message": "Invalid request."
7519     *     }
7520     * 
7521     * @apiSampleRequest off
7522     */
7523    public function counselingGetDisabledDates() {
7524        $this->autoRender = false;
7525        if ($this->request->is('ajax')) {
7526            $data = $this->request->data;
7527            // - get disabled dates
7528            $counselorIds = $this->Teacher->getCounselorId();
7529            $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7530                'userId' => $data['userId'],
7531                'teacherId' => $counselorIds,
7532                'timeDiff' => $this->timeDiff
7533            ));
7534            return json_encode($disabledSchedule);
7535        }
7536    }
7537
7538    /**
7539     * @api {post} /user/waiting/counselorSlots counselorSlots()
7540     * @apiName counselorSlots
7541     * @apiGroup Waiting
7542     * @apiDescription Retrieves the available slots for counseling sessions for the authenticated user in Native Camp. It returns the available slots and their states.
7543     *
7544     * @apiBody {String} userId The ID of the user.
7545     * @apiBody {Boolean} [ifForCancellation=false] Indicates whether the request is for cancellation.
7546     * 
7547     * @apiSuccess {Object} schedules The schedules of available slots.
7548     * @apiSuccess {String} schedules.day The day of the week.
7549     * @apiSuccess {String} schedules.d The day of the month.
7550     * @apiSuccess {String} schedules.m The month.
7551     * @apiSuccess {String} schedules.y The year.
7552     * @apiSuccess {Object} schedules.slots The slots for the day.
7553     * @apiSuccess {Number} schedules.slots.open_counselor The number of open counselors.
7554     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by others, 3: Not available, 4: Fully booked, 5: Can't reserve due to limit, 6: Not available within 10 minutes, 7: Available).
7555     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7556     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7557     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7558     * @apiSuccess {Number} [schedules.slots.limited_plan_reservation] Indicates whether the slot is limited plan reservation (if applicable).
7559     *
7560     * @apiSuccessExample {json} Success-Response:
7561     *     {
7562     *         "schedules": {
7563     *             "12/01": {
7564     *                 "day": "(月)",
7565     *                 "d": "01",
7566     *                 "m": "12",
7567     *                 "y": "2023",
7568     *                 "slots": {
7569     *                     "10:00": {
7570     *                         "open_counselor": 2,
7571     *                         "state": 7,
7572     *                         "hour": 10,
7573     *                         "minute": 0,
7574     *                         "is_reserve": false
7575     *                     },
7576     *                     "10:30": {
7577     *                         "open_counselor": 1,
7578     *                         "state": 1,
7579     *                         "hour": 10,
7580     *                         "minute": 30,
7581     *                         "is_reserve": true
7582     *                     }
7583     *                 }
7584     *             }
7585     *         }
7586     *     }
7587     *
7588     * @apiError {String} status The status of the request (NG).
7589     * @apiError {String} message The error message.
7590     *
7591     * @apiErrorExample {json} Error-Response:
7592     *     {
7593     *         "status": "NG",
7594     *         "message": "Invalid request."
7595     *     }
7596     * 
7597     * @apiSampleRequest off
7598     */
7599    public function counselorSlots() {
7600        // $this->autoRender = false;
7601        $data = $this->request->data;
7602        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7603        $user_id = isset($data['userId']) ? $data['userId'] : '';
7604        $this->set('userId', $user_id);
7605        $nowTime = time();
7606        $userTime = $this->displayTime;
7607        $start_date = date('Y-m-d H:i', $nowTime);
7608        $corporateLightUser = false;
7609        $corporateLimitedUser = false;
7610        $slots = array(
7611            'show_caution_flg' => 0,
7612            'start_date' => $start_date,
7613            'states' => NULL
7614        );
7615        // check corporate user
7616        $getCorporateType = $this->User->find("first",array(
7617                "conditions" => array( "User.id" => $user_id ),
7618                "fields" => array("User.payment_plan_id"),
7619                "recursive" => -1,
7620            )
7621        );
7622        
7623        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7624            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7625            
7626            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7627            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7628        }
7629        $this->set('corporateLimitedUser', $corporateLimitedUser);
7630        $this->set('corporateLightUser', $corporateLightUser);
7631        // - if reservation exceeds cancellation already
7632        $sharedUserDataCorporateType = myTools::getCoporateTypeUsingPaymentPlanId($this->sharedUserData['User']['payment_plan_id']);
7633        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7634        $counselorIds = $this->Teacher->getCounselorId();
7635        $result = $this->LessonSchedule->getCounselorSlots(array(
7636            'counselor_ids' => $counselorIds,
7637            'user_id' => $user_id,
7638            'start_day' => $start_date,
7639            'include_past' => true,
7640            'corporateLimitedUser' => $corporateLimitedUser,
7641            'corporateLightUser' => (isset($sharedUserDataCorporateType) && $sharedUserDataCorporateType == Configure::read("corporate_type.light")) ? true : false
7642        ));
7643
7644        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7645        $openSlots = array();
7646        $schedules = array();
7647
7648        if (!$result['error']) {
7649            // - get days
7650            for ($i=0; $i<=7; $i++) {
7651                $cTime = strtotime("+" . $i . " days", $userTime);
7652                $schedDate = date('m/d', $cTime);
7653                $schedules[$schedDate] = array(
7654                    'day' => $weekday[date("w", $cTime)],
7655                    'd' => date('d', $cTime),
7656                    'm' => date('m', $cTime),
7657                    'y' => date('Y', $cTime)
7658                );
7659            }
7660
7661            // - arrange open_slot
7662            foreach ($result['openSlotData'] as $slot) {
7663                $shiftTime = TimezoneTable::computeTimeToUser(array(
7664                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7665                    'timestamp' => $this->timeDiffSecond
7666                ));
7667                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7668                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7669                $lessonHour = date('H', $shiftTime);
7670                $lessonMinute = date('i', $shiftTime);
7671                $lessonDateTime = explode(' ', $formattedLessonTime);
7672                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7673                $lessonDate = date('m/d', strtotime($lessonDate));
7674                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7675
7676                // - state 7 : Available
7677                $state = 7;
7678
7679                //check before 10minutes
7680                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 600) {
7681                    $state = 6;
7682                }
7683
7684                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7685                    'open_counselor' => intval($slot[0]['shiftCount']),
7686                    'state' => $state,
7687                    'hour' => $lessonHour,
7688                    'minute' => $lessonMinute
7689                );
7690
7691                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7692                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7693                }
7694            }
7695
7696            // - counselor ids
7697            $counselorsIds = !empty($counselorIds) ? array_values($counselorIds) : array();
7698            // - counselor reservations
7699            foreach ($result['reservationData'] as $reservation) {
7700                //get timestamp adjusted to user timezone
7701                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7702                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7703                    'timestamp' => $this->timeDiffSecond
7704                ));
7705                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7706                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7707
7708                $lessonHour = date('H', $unixUserLessonTime);
7709                $lessonMinute = date('i', $unixUserLessonTime);
7710                $lessonDateTime = explode(' ', $formattedUserLessonTime);
7711                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7712                $lessonDate = date('m/d', strtotime($lessonDate));
7713                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7714
7715                // - if my reservation
7716                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
7717                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && !empty($openSlots[$timeIndex])) {
7718                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
7719                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && empty($openslot[$timeIndex])) {
7720                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
7721                    } else {
7722                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
7723                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7724                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7725                    }
7726
7727                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
7728
7729                // - if not my reservations
7730                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
7731                    $openSlots[$timeIndex]--;
7732
7733                    # to prevent the schedule of the current user being overriden by other users schedules
7734                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
7735                        continue;
7736                    }
7737
7738                    if (
7739                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
7740                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
7741                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
7742                    ) {
7743                        $openSlots[$timeIndex]--;
7744                        // - state 5 : can't reserve because of reservation limit
7745                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7746                            'state' => 5,
7747                            'open_counselor' => intval($openSlots[$timeIndex]),
7748                            'hour' => $lessonHour,
7749                            'minute' => $lessonMinute
7750                        );
7751
7752                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
7753                        // - state 7 : Available
7754                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7755                            'state' => 7,
7756                            'open_counselor' => intval($openSlots[$timeIndex]),
7757                            'hour' => $lessonHour,
7758                            'minute' => $lessonMinute
7759                        );
7760                    } elseif (
7761                        isset($openSlots[$timeIndex])
7762                        && $openSlots[$timeIndex] <= 0
7763                        && (
7764                            isset($schedules[$formattedLessonTime]['state'])
7765                            && $schedules[$formattedLessonTime]['state'] >= 4
7766                            || empty($schedules[$formattedLessonTime]['state'])
7767                        )
7768                    ) {
7769                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
7770                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7771                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7772                    }
7773                }
7774            }
7775
7776            if ($ifForCancellation) {
7777                $this->autoRender = false;
7778                return json_encode($schedules);
7779            }
7780            $this->set('schedules', $schedules);
7781        }
7782    }
7783
7784    /**
7785     * @api {post} /user/waiting/avatarSlots avatarSlots()
7786     * @apiName avatarSlots
7787     * @apiGroup Waiting
7788     * @apiDescription Retrieves the available slots for avatar lessons for the authenticated user in Native Camp. It returns the schedule and availability of the slots.
7789     *
7790     * @apiBody {String} teacherId The ID of the avatar teacher.
7791     * @apiBody {Boolean} [ifForCancellation] Indicates whether the request is for cancellation.
7792     * @apiBody {String} userId The ID of the user.
7793     * 
7794     * @apiSuccess {Object} schedules The schedule and availability of the slots.
7795     * @apiSuccess {String} schedules.day The day of the week.
7796     * @apiSuccess {String} schedules.d The day of the month.
7797     * @apiSuccess {String} schedules.m The month.
7798     * @apiSuccess {String} schedules.y The year.
7799     * @apiSuccess {Object} schedules.slots The slots for each day.
7800     * @apiSuccess {Number} schedules.slots.open_avatar The number of open avatar slots.
7801     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by another user, 3: Reserved by another user and not available, 4: No open slots, 5: Can't reserve because of reservation limit, 6: Can't reserve because it's within 5 minutes, 7: Available).
7802     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7803     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7804     * @apiSuccess {Object} [schedules.slots.teacherData] The data of the teacher for the slot.
7805     * @apiSuccess {Object} [schedules.slots.ownTeacherData] The data of the user's own teacher for the slot.
7806     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7807     * @apiSuccess {String} schedules.slots.teacher_id The ID of the teacher for the slot.
7808     * @apiSuccess {Object} campaignPeriod The campaign period for the avatar teacher.
7809     * @apiSuccess {String[]} times The available times for the slots.
7810     *
7811     * @apiSuccessExample {json} Success-Response:
7812     *     {
7813     *         "schedules": {
7814     *             "12/01": {
7815     *                 "day": "(月)",
7816     *                 "d": "01",
7817     *                 "m": "12",
7818     *                 "y": "2023",
7819     *                 "slots": {
7820     *                     "10:00": {
7821     *                         "open_avatar": 2,
7822     *                         "state": 7,
7823     *                         "hour": 10,
7824     *                         "minute": 0
7825     *                     },
7826     *                     "10:30": {
7827     *                         "open_avatar": 1,
7828     *                         "state": 1,
7829     *                         "hour": 10,
7830     *                         "minute": 30,
7831     *                         "ownTeacherData": {
7832     *                             "id": "123",
7833     *                             "name": "John Doe",
7834     *                             "image": "https://www.nativecamp.net/img/teacher/123.jpg"
7835     *                         }
7836     *                     }
7837     *                 }
7838     *             }
7839     *         },
7840     *         "campaignPeriod": {...},
7841     *         "times": ["00:00", "00:30", "01:00", ...]
7842     *     }
7843     *
7844     * @apiError {String} status The status of the request (NG).
7845     * @apiError {Number} content The content of the response (0: No issues).
7846     *
7847     * @apiErrorExample {json} Error-Response:
7848     *     {
7849     *         "status": "NG",
7850     *         "content": 0
7851     *     }
7852     * 
7853     * @apiSampleRequest off
7854     */
7855    public function avatarSlots() {
7856        
7857        $data = $this->request->data;
7858        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : '';
7859        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7860        $user_id = isset($data['userId']) ? $data['userId'] : '';
7861        $this->set('userId', $user_id);
7862        $this->set('currentAvatarId', $teacherId);
7863        $nowTime = time();
7864        $userTime = $this->displayTime;
7865        $start_date = date('Y-m-d H:i', $nowTime);
7866        $corporateLightUser = false;
7867        $corporateLimitedUser = false;
7868        $slots = array(
7869            'show_caution_flg' => 0,
7870            'start_date' => $start_date,
7871            'states' => NULL
7872        );
7873        // check corporate user
7874        $getCorporateType = $this->User->find("first",array(
7875                "conditions" => array( "User.id" => $user_id ),
7876                "fields" => array("User.payment_plan_id"),
7877                "recursive" => -1,
7878            )
7879        );
7880
7881        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7882            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7883            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7884            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7885        }
7886
7887        $this->set('corporateLightUser', $corporateLightUser);
7888        $this->set('corporateLimitedUser', $corporateLimitedUser);
7889        // - if reservation exceeds cancellation already
7890        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7891        $getAvatarParams = array(
7892            "avatar_id" => $teacherId,
7893            "user_id" => $user_id,
7894            "stealth_flg" => $this->Cookie->read('stealth.setting'),
7895            'corporateLimitedUser' => $corporateLimitedUser
7896        );
7897        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
7898        $result = $this->LessonSchedule->getAvatarSlots(array(
7899            'avatar_ids' => $avatarTeacherIds,
7900            'user_id' => $user_id,
7901            'start_day' => $start_date,
7902            'include_past' => true,
7903            'corporateLimitedUser' => $corporateLimitedUser
7904        ));
7905
7906        //campaign period start and end time
7907        $campaignPeriod = null;
7908        $checkAvatarPop = $this->userAvailPopularTeacher(
7909            array(
7910                'avatar_id' => $teacherId,
7911                'user_id' => $this->Auth->user('id'),
7912                "stealth_flg" => $this->Cookie->read('stealth.setting')
7913            )
7914        );
7915        if ($result && $checkAvatarPop) {
7916            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
7917                'user_id' => $this->Auth->user('id'),
7918                'teacher_id' => $teacherId
7919            ));
7920        }
7921
7922        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7923        $openSlots = array();
7924        $schedules = array();
7925        $tempSchedules = array();
7926
7927        if (!$result['error']) {
7928            // - get days
7929            for ($i=0; $i<=7; $i++) {
7930                $cTime = strtotime("+" . $i . " days", $userTime);
7931                $schedDate = date('m/d', $cTime);
7932                $schedules[$schedDate] = array(
7933                    'day' => $weekday[date("w", $cTime)],
7934                    'd' => date('d', $cTime),
7935                    'm' => date('m', $cTime),
7936                    'y' => date('Y', $cTime)
7937                );
7938            }
7939
7940            // - arrange open_slot
7941            foreach ($result['openSlotData'] as $slot) {
7942                $shiftTime = TimezoneTable::computeTimeToUser(array(
7943                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7944                    'timestamp' => $this->timeDiffSecond
7945                ));
7946                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7947                $openSlotsTemp[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7948                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7949                $lessonHour = date('H', $shiftTime);
7950                $lessonMinute = date('i', $shiftTime);
7951                $lessonDateTime = explode(' ', $formattedLessonTime);
7952                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7953                $lessonDate = date('m/d', strtotime($lessonDate));
7954                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7955
7956                // - state 7 : Available
7957                $state = 7;
7958
7959                //check before 5minutes
7960                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 300) {
7961                    $state = 6;
7962                }
7963
7964                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7965                    'open_avatar' => intval($slot[0]['shiftCount']),
7966                    'state' => $state,
7967                    'hour' => $lessonHour,
7968                    'minute' => $lessonMinute
7969                );
7970
7971                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($slot[0]['shiftCount']);
7972
7973                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7974                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7975                }
7976            }
7977
7978
7979
7980            // - counselor ids
7981            $avatarTeacherIds = !empty($avatarTeacherIds) ? array_values($avatarTeacherIds) : array();
7982            // - counselor reservations
7983            $userSchedules = [];
7984            $otherUserSchedules = [];
7985            foreach ($result['reservationData'] as $reservation) {
7986                //get timestamp adjusted to user timezone
7987                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7988                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7989                    'timestamp' => $this->timeDiffSecond
7990                ));
7991                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7992                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7993
7994                $lessonHour = date('H', $unixUserLessonTime);
7995                $lessonMinute = date('i', $unixUserLessonTime);
7996                $lessonDateTime = explode(' ', $formattedUserLessonTime);
7997                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7998                $lessonDate = date('m/d', strtotime($lessonDate));
7999                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
8000                $lsDateTime = date('Y-m-d H:i', strtotime($reservation['LessonSchedule']['lesson_time']));
8001
8002                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = $openSlotsTemp[$timeIndex]--;
8003
8004                // - if another user reservation
8005                if ($reservation['LessonSchedule']['user_id'] != $user_id) {
8006                    $otherUserSchedules[$lessonDate][$lessonTime] = true;
8007                }
8008
8009                // - if my reservation
8010                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
8011                    $userSchedules[$lessonDate][] = $lessonTime;
8012                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && !empty($openSlots[$timeIndex])) {
8013                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8014                        //get teacher details for other reservation
8015                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8016                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8017                        $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $teacherData;
8018                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && empty($openslot[$timeIndex])) {
8019                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
8020                    } else {
8021                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8022                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8023                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8024
8025                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8026                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8027                        $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $teacherData;
8028                    }
8029
8030                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
8031                    $schedules[$lessonDate]['slots'][$lessonTime]['teacher_id'] = $reservation['LessonSchedule']['teacher_id'];
8032
8033                // - if not my reservations
8034                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
8035                    $openSlots[$timeIndex]--;
8036
8037                    if( isset($reservation['ShiftWorkOn']['hide_flg']) && $reservation['ShiftWorkOn']['hide_flg'] ) {
8038                        $openSlots[$timeIndex]++;
8039                    }
8040                    
8041                    # to prevent the schedule of the current user being overriden by other users schedules
8042                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
8043                        continue;
8044                    }
8045
8046                    if (
8047                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
8048                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
8049                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
8050                    ) {
8051                        $openSlots[$timeIndex]--;
8052                        // - state 5 : can't reserve because of reservation limit
8053                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8054                            'state' => 5,
8055                            'hour' => $lessonHour,
8056                            'minute' => $lessonMinute,
8057                            'open_avatar' => intval($openSlots[$timeIndex])
8058                        );
8059
8060                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
8061                        // - state 7 : Available
8062                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8063                            'state' => 7,
8064                            'hour' => $lessonHour,
8065                            'minute' => $lessonMinute,
8066                            'open_avatar' => intval($openSlots[$timeIndex])
8067                        );
8068                    } elseif (
8069                        isset($openSlots[$timeIndex])
8070                        && $openSlots[$timeIndex] <= 0
8071                        && (
8072                            isset($schedules[$formattedLessonTime]['state'])
8073                            && $schedules[$formattedLessonTime]['state'] >= 4
8074                            || empty($schedules[$formattedLessonTime]['state'])
8075                        )
8076                    ) {
8077                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
8078                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8079                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8080                        $schedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($openSlots[$timeIndex]);
8081                    }
8082                }
8083            }
8084
8085            // User priority, override display schedules state
8086            foreach ($userSchedules as $lesson_date => $slots) {
8087                foreach ($slots as $lesson_time) {
8088                    // Override state when slot reserved by other
8089                    if(!empty($state = $schedules[$lesson_date]['slots'][$lesson_time]['state']) && $state === 2
8090                        && !empty($otherUserSchedules[$lesson_date][$lesson_time])) {
8091                        $schedules[$lesson_date]['slots'][$lesson_time]['state'] = 3;
8092                    }
8093                    $schedules[$lesson_date]['slots'][$lesson_time]['open_avatar'] = $tempSchedules[$lesson_date]['slots'][$lesson_time]['open_avatar'];
8094                }
8095
8096            }
8097
8098            $resData = $this->LessonSchedule->getHiddenReservation([
8099                'user_id' => $user_id
8100            ]);
8101
8102            if ($resData) {
8103                foreach ($resData as $key => $row) {
8104                    //get timestamp adjusted to user timezone
8105                    $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
8106                        'time' => strtotime($key),
8107                        'timestamp' => $this->timeDiffSecond
8108                    ));
8109                    $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
8110                    $lessonDate = date('m/d', $unixUserLessonTime);
8111                    $lessonTime = date('H:i', $unixUserLessonTime);
8112
8113                    if (
8114                        !empty($openSlots[$timeIndex]) && 
8115                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['teacherData']) &&
8116                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'])
8117                    ) {
8118
8119                        $lessonRequestSlotData = $this->LessonSchedule->getReservationData($key, $user_id, $this->localizeDir);
8120                        if (!empty($lessonRequestSlotData)) {
8121                            $lessonRequestSlotData['icon_color']  = $this->LessonSchedule->getIconColor($lessonRequestSlotData, $key);
8122
8123                            if (in_array($lessonRequestSlotData['teacher_id'], $avatarTeacherIds) && $lessonRequestSlotData['reservation_status'] == Configure::read('lesson_schedule.status.on_reserve')) {
8124                                $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $lessonRequestSlotData;
8125                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8126                            } else {
8127                                $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $lessonRequestSlotData;
8128                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8129                            }
8130                        }
8131                    }
8132                }
8133            } 
8134
8135            if ($ifForCancellation) {
8136                $this->autoRender = false;
8137                return json_encode($schedules);
8138            }
8139            
8140            // NJ-33414
8141            $this->UsersDetail->openDBReplica();
8142            $fetchUsersDetail = $this->UsersDetail->find('first', array(
8143                'fields' => array(
8144                    'lesson_request_flg'
8145                ),
8146                'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
8147                'recursive' => -1
8148            ));
8149            $this->UsersDetail->closeDBReplica();
8150            
8151            $times = array();
8152            $utcMin = explode(':', $this->utcOffset);
8153            if ($utcMin[1] == "45") {
8154                for ($i=0; $i<=23; $i++) {
8155                    $times[] = sprintf("%02d",$i) . ':15';
8156                    $times[] = sprintf("%02d",$i) . ':45';
8157                }
8158            } else {
8159                for ($i=0; $i<=23; $i++) {
8160                    $times[] = sprintf("%02d",$i) . ':00';
8161                    $times[] = sprintf("%02d",$i) . ':30';
8162                }
8163            }
8164            $this->set('times', $times);
8165            $this->set('teacherId', $teacherId);
8166            $this->set('schedules', $schedules);
8167            $this->set('campaignPeriod', $campaignPeriod);
8168        }
8169    }
8170
8171    /**
8172     * @api {post} /user/waiting/counselingLimit counselingLimit()
8173     * @apiName counselingLimit
8174     * @apiGroup Waiting
8175     * @apiDescription Checks the reservation and cancellation limits for counseling sessions for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8176     *
8177     * @apiBody {String} action The action to perform (add or cancel).
8178     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8179     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8180     * 
8181     * @apiSuccess {String} status The status of the request (OK or NG).
8182     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds counselor reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8183     * @apiSuccess {Object} lastDetails The last counseling details.
8184     * @apiSuccess {Number} lastDetails.id The ID of the last counseling session.
8185     * @apiSuccess {String} lastDetails.lesson_time The time of the last counseling session.
8186     * @apiSuccess {Number} lastDetails.teacher_id The ID of the teacher for the last counseling session.
8187     * @apiSuccess {Number} lastDetails.user_id The ID of the user for the last counseling session.
8188     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8189     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8190     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8191     * @apiSuccess {Boolean} isExpired Indicates whether the user's coin has expired.
8192     * 
8193     * @apiSuccessExample {json} Success-Response:
8194     *     {
8195     *         "status": "OK",
8196     *         "content": 0,
8197     *         "lastDetails": {
8198     *             "id": 123456,
8199     *             "lesson_time": "2023-12-01 12:00:00",
8200     *             "teacher_id": 123,
8201     *             "user_id": 123
8202     *         },
8203     *         "cancelCount": 1,
8204     *         "displayNotice": 0,
8205     *         "nextChargeDate": "2023年12月01日",
8206     *         "isExpired": false
8207     *     }
8208     *
8209     * @apiError {String} status The status of the request (NG).
8210     * @apiError {Number} content The content of the response (0: No issues).
8211     * @apiError {Number} cancelCount The count of cancellations by the user.
8212     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8213     *
8214     * @apiErrorExample {json} Error-Response:
8215     *     {
8216     *         "status": "NG",
8217     *         "content": 0,
8218     *         "cancelCount": 0,
8219     *         "displayNotice": 0
8220     *     }
8221     * 
8222     * @apiSampleRequest off
8223     */
8224    public function counselingLimit() {
8225        $this->autoRender = false;
8226        if ($this->request->is('ajax')) {
8227
8228            $userCancelledReservation = 0;
8229            $userId = $this->Auth->user('id');
8230            $action = $this->request->data['action'];
8231            $content = 0;
8232            if ($action == 'add') {
8233
8234                if (empty($this->request->data['lessonDate'])) {
8235                    return json_encode(array(
8236                        'status' => 'NG',
8237                        'content' => 0
8238                    ));
8239                }
8240
8241                // if complimentary user plan
8242                $user = $this->sharedUserData['User'];
8243                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8244                    $this->loadModel('ComplimentaryCode');
8245                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8246                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8247                        // set beyond available days to true
8248                        return json_encode(array('status' => 'OK', 'content' => 5));
8249                    }
8250                }
8251
8252                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8253
8254                // NC-7361 - corporate light
8255                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8256                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8257                        return json_encode(array('status' => 'OK', 'content' => 6));
8258                    }
8259                }
8260
8261                // - get total reservation
8262                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8263
8264                // - check if total reservation exceeds limit
8265                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8266                    $content = 2;
8267                } else {
8268                    // - show caution flag
8269                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8270                        'userId' => $userId,
8271                        'timestamp' => $this->timeDiffSecond
8272                    ));
8273
8274                    // - check reservation limit 4reservations/day
8275                    $totalReservationCounselor = $this->LessonSchedule->countUserReservationForTeacherCounselor(array(
8276                        'userId' => $userId,
8277                        'lessonDate' => $this->request->data['lessonDate'],
8278                        'timeDiffSecond' => $this->timeDiffSecond
8279                    ));
8280
8281                    // - check counselor reservations per day limit
8282                    if ($totalReservationCounselor >= 4) {
8283                        $content = 3;
8284
8285                    // - check caution flag and not yet over 20 max limit total reservation
8286                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8287                        $content = 1;
8288                    }
8289                }
8290
8291            } else {
8292                // - count total cancellations
8293                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8294                if ($userCancelledReservation >= 3) {
8295                    $content = 4;
8296                }
8297
8298                // cancel in time not allowed
8299                if(!empty($this->request->data['lessonTime']) && !$content){
8300
8301                    // if time >= lesson time(server time)
8302                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8303                        $content = 7;
8304                    }
8305                }
8306            }
8307            // get user counseling attended flag status
8308            $userData = $this->User->getUserData(
8309                array('User.id' => $userId),
8310                array(
8311                    'User.counseling_attended_flg',
8312                    'User.next_charge_date'
8313                ),
8314                'first'
8315            );
8316
8317            $nextChargeDate = "";
8318            if (isset($userData['User']['next_charge_date'])) {
8319                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8320                    'time' => strtotime($userData['User']['next_charge_date']),
8321                    'timestamp' => $this->timeDiffSecond
8322                ));
8323                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8324            }
8325            //This will be get last records for counselor details
8326            $getLastDetails = $this->Counseling->getLastCounselingById($userId);
8327
8328            $params23 = array(
8329                'user_id' => $userId,
8330                'lesson_time' =>  $this->request->data['lessonTime']
8331            );
8332            $lsId = $this->LessonSchedule->counselorCheckExpiredCoin($params23);
8333
8334            // NC-8428 - check if user has user point history record
8335            $_lsId = isset($lsId['LessonSchedule']['id']) ? $lsId['LessonSchedule']['id'] : null;
8336            $pointParam = array(
8337                'log_id' => $_lsId,
8338                'user_id' => $userId,
8339                'kbn_type' => 2, // coin  use
8340                'expiration_flg' => 2,
8341                'payment_plan_id' => isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null
8342            );
8343            $isExpired = ClassRegistry::init('UsersPointHistory')->checkCoinExpiration($pointParam);
8344
8345            return json_encode(array(
8346                'status' => 'OK',
8347                'content' => $content,
8348                'lastDetails' => $getLastDetails,
8349                'cancelCount' => $userCancelledReservation,
8350                'displayNotice' => (isset($userData['User']['counseling_attended_flg'])) ? $userData['User']['counseling_attended_flg'] : 0,
8351                'nextChargeDate' => $nextChargeDate,
8352                'isExpired' => $isExpired,
8353            ));
8354        } else {
8355            return json_encode(array(
8356                'status' => 'NG',
8357                'content' => 0,
8358                'cancelCount' => 0,
8359                'displayNotice' => 0
8360            ));
8361        }
8362    }
8363
8364    /**
8365     * @api {post} /user/waiting/avatarLimit avatarLimit()
8366     * @apiName avatarLimit
8367     * @apiGroup Waiting
8368     * @apiDescription Checks the reservation and cancellation limits for avatar lessons for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8369     *
8370     * @apiBody {String} action The action to perform (add or cancel).
8371     * @apiBody {String} teacher_avatar The ID of the avatar teacher.
8372     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8373     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8374     * 
8375     * @apiSuccess {String} status The status of the request (OK or NG).
8376     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds avatar reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8377     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8378     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8379     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8380     *
8381     * @apiSuccessExample {json} Success-Response:
8382     *     {
8383     *         "status": "OK",
8384     *         "content": 0,
8385     *         "cancelCount": 1,
8386     *         "displayNotice": 0,
8387     *         "nextChargeDate": "2023年12月01日"
8388     *     }
8389     *
8390     * @apiError {String} status The status of the request (NG).
8391     * @apiError {Number} content The content of the response (0: No issues).
8392     * @apiError {Number} cancelCount The count of cancellations by the user.
8393     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8394     *
8395     * @apiErrorExample {json} Error-Response:
8396     *     {
8397     *         "status": "NG",
8398     *         "content": 0,
8399     *         "cancelCount": 0,
8400     *         "displayNotice": 0
8401     *     }
8402     * 
8403     * @apiSampleRequest off
8404     */
8405    public function avatarLimit() {
8406        $this->autoRender = false;
8407        if ($this->request->is('ajax')) {
8408
8409            $userCancelledReservation = 0;
8410            $userId = $this->Auth->user('id');
8411            $action = $this->request->data['action'];
8412            $teacherAvatarId = $this->request->data['teacher_avatar'];
8413            $content = 0;
8414            if ($action == 'add') {
8415
8416                if (empty($this->request->data['lessonDate'])) {
8417                    return json_encode(array(
8418                        'status' => 'NG',
8419                        'content' => 0
8420                    ));
8421                }
8422
8423                // if complimentary user plan
8424                $user = $this->sharedUserData['User'];
8425                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8426                    $this->loadModel('ComplimentaryCode');
8427                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8428                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8429                        // set beyond available days to true
8430                        return json_encode(array('status' => 'OK', 'content' => 5));
8431                    }
8432                }
8433
8434                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8435
8436                // NC-7361 - corporate light
8437                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8438                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8439                        return json_encode(array('status' => 'OK', 'content' => 6));
8440                    }
8441                }
8442
8443                // - get total reservation
8444                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8445
8446                // - check if total reservation exceeds limit
8447                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8448                    $content = 2;
8449                } else {
8450                    // - show caution flag
8451                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8452                        'userId' => $userId,
8453                        'timestamp' => $this->timeDiffSecond
8454                    ));
8455
8456                    // - check reservation limit 4reservations/day
8457                    $totalReservationAvatar = $this->LessonSchedule->countUserReservationForTeacherAvatar(array(
8458                        'avatar_id' => $teacherAvatarId,
8459                        'userId' => $userId,
8460                        'lessonDate' => $this->request->data['lessonDate'],
8461                        'timeDiffSecond' => $this->timeDiffSecond
8462                    ));
8463
8464                    // - check avatar reservations per day limit
8465                    if ($totalReservationAvatar >= 4) {
8466                        $content = 3;
8467
8468                    // - check caution flag and not yet over 20 max limit total reservation
8469                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8470                        $content = 1;
8471                    }
8472                }
8473
8474            } else {
8475                // - count total cancellations
8476                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8477                if ($userCancelledReservation >= 3) {
8478                    $content = 4;
8479                }
8480
8481                // cancel in time not allowed
8482                if(!empty($this->request->data['lessonTime']) && !$content){
8483
8484                    // if time >= lesson time(server time)
8485                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8486                        $content = 7;
8487                    }
8488                }
8489            }
8490            // get user
8491            $userData = $this->User->getUserData(
8492                array('User.id' => $userId),
8493                array(
8494                    'User.next_charge_date'
8495                ),
8496                'first'
8497            );
8498
8499            $nextChargeDate = "";
8500            if (isset($userData['User']['next_charge_date'])) {
8501                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8502                    'time' => strtotime($userData['User']['next_charge_date']),
8503                    'timestamp' => $this->timeDiffSecond
8504                ));
8505                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8506            }
8507
8508            return json_encode(array(
8509                'status' => 'OK',
8510                'content' => $content,
8511                'cancelCount' => $userCancelledReservation,
8512                'displayNotice' => 0,
8513                'nextChargeDate' => $nextChargeDate
8514            ));
8515        } else {
8516            return json_encode(array(
8517                'status' => 'NG',
8518                'content' => 0,
8519                'cancelCount' => 0,
8520                'displayNotice' => 0
8521            ));
8522        }
8523    }
8524
8525    /**
8526     * @api {post} /user/waiting/checkCounselingReservationNow checkCounselingReservationNow()
8527     * @apiName checkCounselingReservationNow
8528     * @apiGroup Waiting
8529     * @apiDescription Checks if the user has a reserved counseling session at the current time. It returns the status of the reservation and the teacher's information if available.
8530     *
8531     * @apiBody {String} userId The ID of the user.
8532     * 
8533     * @apiSuccess {String} status The status of the request (OK or NG).
8534     * @apiSuccess {Number} [state] The state of the counseling reservation (1: No reserved counseling, 2: Reserved counseling and teacher is on standby, 3: Reserved counseling and teacher is not on standby).
8535     * @apiSuccess {String} [teacher_id] The ID of the teacher (if state is 2).
8536     * @apiSuccess {String} [chat_hash] The chat hash of the lesson (if state is 2).
8537     *
8538     * @apiSuccessExample {json} Success-Response:
8539     *     {
8540     *         "status": "OK",
8541     *         "state": 2,
8542     *         "teacher_id": "123",
8543     *         "chat_hash": "example_chat_hash"
8544     *     }
8545     *
8546     * @apiError {String} status The status of the request (NG).
8547     *
8548     * @apiErrorExample {json} Error-Response:
8549     *     {
8550     *         "status": "NG"
8551     *     }
8552     * 
8553     * @apiSampleRequest off
8554     */
8555    public function checkCounselingReservationNow() {
8556        $this->autoRender = false;
8557        $data = $this->request->data;
8558        $result = array('status' => 'OK');
8559
8560        if (empty($data['userId'])) {
8561            return json_encode(array(
8562                'status' => 'NG'
8563            ));
8564        }
8565
8566        if ($this->request->is('ajax')) {
8567            //target lesson schedule start time
8568            $minutes = date('i');
8569            if ($minutes >= 0 && $minutes < 26) {
8570                $lessonTime = date('Y-m-d H:00:00');
8571            } elseif ($minutes >= 30 && $minutes < 56) {
8572                $lessonTime = date('Y-m-d H:30:00');
8573            } else {
8574                // - [1] if user has no reserved counseling
8575                $result['state'] = 1;
8576                return json_encode($result);
8577            }
8578
8579            // - check ongoing lesson
8580            $counselingInfo = $this->LessonSchedule->find('first', array(
8581                    'fields' => array(
8582                        'LessonSchedule.id',
8583                        'LessonOnair.teacher_id',
8584                        'LessonOnair.chat_hash'
8585                    ),
8586                    'conditions' => array(
8587                        'LessonSchedule.lesson_time' => $lessonTime,
8588                        'LessonSchedule.user_id' => $data['userId']
8589                    ),
8590                    'joins' => array(
8591                        array(
8592                            'type' => 'LEFT',
8593                            'table' => 'lesson_onairs',
8594                            'alias' => 'LessonOnair',
8595                            'conditions' => array('LessonSchedule.teacher_id = LessonOnair.teacher_id AND LessonOnair.connect_flg = 1')
8596                        ),
8597                        array(
8598                            'type' => 'INNER',
8599                            'table' => 'teachers',
8600                            'alias' => 'Teacher',
8601                            'conditions' => array('Teacher.id = LessonOnair.teacher_id AND Teacher.counseling_flg = 1')
8602                        )
8603                    ),
8604                    'recursive' => -1
8605                )
8606            );
8607
8608            // - [1] if user has no reserved counseling
8609            if (empty($counselingInfo)) {
8610                $result['state'] = 1;
8611                return json_encode($result);
8612            }
8613
8614            // - [2] if user has reserved counseling and teacher is on standby
8615            if (!empty($counselingInfo['LessonOnair']['chat_hash'])) {
8616                $result['state'] = 2;
8617                $result['teacher_id'] = $counselingInfo['LessonOnair']['teacher_id'];
8618                $result['chat_hash'] = $counselingInfo['LessonOnair']['chat_hash'];
8619                return json_encode($result);
8620
8621            // - [3] if user has reserved counseling and teacher is not on standby
8622            } elseif (empty($counselingInfo['LessonOnair']['chat_hash'])) {
8623                $result['state'] = 3;
8624                return json_encode($result);
8625            } else {
8626                $result['state'] = 1;
8627                return json_encode($result);
8628            }
8629
8630        } else {
8631            return json_encode(array(
8632                'status' => 'NG'
8633            ));
8634        }
8635    }
8636
8637
8638    //Retrieves the details of a specific teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
8639    public function spDetail($teacherId) {
8640        if (!intval($teacherId)) {
8641            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8642        }
8643
8644        // NJ-10759: redirect to mypage if teacher detail sp is counseling and access from teacher mobapp
8645        // redirect if counseling teacher
8646        $counselorParams = array(
8647            'type' => 'count',
8648            'args' => array(
8649                'conditions' => array(
8650                    'id' => $teacherId,
8651                    'counseling_flg' => 1
8652                ),
8653                'recursive' => -1
8654            )
8655        );
8656
8657
8658        // - NC-3802: redirect to mypage if counselor teacher
8659        if ($this->Teacher->getTeachers($counselorParams)) {
8660            return $this->redirect(myTools::getUrl() . '/user/mypage');
8661        }
8662
8663        //fetch teacher data
8664        $data = $this->Teacher->findById($teacherId);
8665
8666        //no teacher data
8667        if (!$data) {
8668            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8669        }
8670
8671        // //check company ip and if the teacher is stealth on redirect to teacher list
8672        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
8673        //     return $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
8674        // }
8675
8676        //redirect if withdrawn teacher
8677        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1) {
8678            return $this->redirect(myTools::geturl() . '/waiting');
8679        }
8680
8681        if(in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
8682            return $this->redirect('/waiting');
8683        }
8684
8685        // - check if blocked student
8686        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
8687            return $this->redirect('/waiting');
8688        }
8689
8690        // - NC-7031: redirect avatar
8691        $avatarData = $this->isAvatar($teacherId);
8692
8693        if ($avatarData) {
8694            $getAId = $avatarData;
8695            return $this->redirect('/avatar_detail/'.$getAId);
8696        }
8697
8698        //lesson onair
8699        $onair1 = $this->LessonOnair->find('first', array(
8700            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
8701            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
8702        ));
8703
8704        //teacher_status if login or break
8705        $teacherStatus1 = $this->TeacherStatus->find('first', array(
8706            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
8707            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
8708            );
8709        // get counrty details
8710        $teacherCountryDetails = $this->CountryCode->find('first', array(
8711            'fields' => array('country_name', 'nationality', 'code'),
8712            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
8713            );
8714
8715        //get own reviews
8716        $selfReviews = array();
8717        $selfLessonCount = 0;
8718        $selfLessonNow = 0;
8719        $selfReservation = 0;
8720        $daysPast = 0;
8721        $userId = $this->Auth->user('id');
8722        $this->set('userId', $userId);
8723        if ($userId) {
8724            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
8725            $selfReviews = $this->getUserReviews($userId, $teacherId);
8726            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
8727            $selfLessonNow = $userLessonDetail['lessonCount'];
8728            $selfReservation = $userLessonDetail['reserveCount'];
8729            $selfLessonCount = $selfLessonNow + $selfReservation;
8730            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
8731        }
8732
8733        if (!empty($onair1)) {
8734            $onair = new LessonOnairTable($onair1['LessonOnair']);
8735        } elseif (!empty($teacherStatus1)) {
8736            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
8737        } else {
8738            $onair = 0;
8739        }
8740
8741        $rateBreakdown = null;
8742        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
8743        if ($rating) {
8744            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
8745            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
8746        }
8747
8748        $this->set('onair', $onair);
8749        $this->set('teacher_id', $teacherId);
8750
8751        $teacher = new TeacherTable($data['Teacher']);
8752        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
8753        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
8754        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
8755        $this->set('teacher', $teacher);
8756
8757        # get weekly rating
8758        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
8759        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
8760            $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
8761        }
8762
8763        //number of lesson
8764        $lessonCount = (int)$teacher->lesson_count;
8765
8766        // Translate and save translated data
8767        $globalTranslate = TeacherTable::translate(array(
8768            'id' => $teacher->id,
8769            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
8770            'controller' => static::class
8771        ));
8772        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
8773        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
8774        $this->set('message', $translatedMessageTranslation);
8775        $this->set('intro', $translatedThirdppTranslation);
8776
8777        // NJ-32759
8778        $userLang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
8779        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
8780        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
8781        $residenceData = $this->getResidenceData($getCRData);
8782        $this->set('residenceData',$residenceData);
8783        $this->set('residenceFlg',$residenceData['countryFlag']);
8784
8785        // get teacher strength feature items
8786        $strengthItemsParams = array(
8787            'teacherId' => $teacherId,
8788            'type' => 0,
8789            'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
8790            'limit' => 3
8791        );
8792        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
8793        $this->set('showRating', $showRating);
8794        $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
8795        $this->set('strengthItems', $strengthItems);
8796        
8797        // - prepare head text
8798        $headTextWD = $pageTitleWD = $teacher->name;
8799        $metaDescWD = "";
8800        if ($this->localizeDir == Configure::read('default.user_language')) {
8801            $headTextWD .= '('.$teacher->jp_name.')';
8802            $pageTitleWD .=  '('.$teacher->jp_name.')';
8803            //$metaDescWD .= '('.$teacher->jp_name.')';
8804        }
8805
8806        //find the selfintro 
8807        $TeacherTable = new TeacherTable($teacher);
8808        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
8809        $_userSelfIntro = strip_tags($_userSelfIntro); 
8810
8811        //prepare meta image 
8812        $_teacherImgUrl = $teacher->getImageUrl();
8813
8814        //check if teacher has no image 
8815        if (empty($teacher->image_url) || !$teacher->image_url) {
8816            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
8817            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
8818        }
8819
8820        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
8821        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
8822        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
8823        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
8824
8825
8826        // NJ-3786 textbook teacher recommendation
8827        $curDate = date('Y-m-d');
8828        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
8829        $txtTeacherRecommendlimit = 10;
8830        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
8831        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
8832        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
8833
8834        if( $userId ) {
8835            $teacherObj = new TeacherTable($data['Teacher']);
8836            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 'user_id' => $userId ) );
8837            $textbookCategoryId = $lastBookUsedData['category_id'];
8838            $textbookBadge = $lastBookUsedData['textbook_badge'];
8839            $paramsArr = array(
8840                'user_id' => $userId,
8841                'begin_date' => $beginDate,
8842                'end_date' => $endDate,
8843                'textbook_category' => $textbookCategoryId,
8844                'textbook_badge' => $textbookBadge,
8845                'limit' => $txtTeacherRecommendlimit,
8846                'user_data' => $userData,
8847                'exclude_teacher_id' => $teacherId
8848            );
8849
8850            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
8851            if( $teacherTextbookStatData ) {
8852                $dataList = $this->arrangeTeacherRecommendList( array( 
8853                        'user_id' => $userId,
8854                        'data' => $teacherTextbookStatData,
8855                        'category_id' => $textbookCategoryId,
8856                        'user_data' => $userData
8857                    ) 
8858                );
8859                $this->set('textbookTeacherData', $dataList);
8860            }
8861
8862            // - user callan unli option flg
8863            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
8864
8865            // - user native unli option flg
8866            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
8867
8868            $can_use_callan_option = 0;
8869            if($callan_option || $native_option) {
8870                $can_use_callan_option = 1;
8871            }
8872
8873            $this->set('can_use_callan_option', $can_use_callan_option);
8874
8875            // - teacher callan unli option flg
8876            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
8877            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
8878            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
8879            
8880            // - check if has callan badge
8881            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
8882            $this->set('teacher_callan_badge', $teacher_callan_badge);
8883        }
8884
8885        // - set page meta information
8886        $this->set('headtext', $headTextWD);
8887        $this->set('title_for_layout', $pageTitleWD);
8888        $this->set('meta_description', $metaDescWD);
8889        $this->set('lessonCount', $lessonCount);
8890        $this->set('country', $country);
8891        $this->set('rateBreakdown', $rateBreakdown);
8892        $this->set('selfReviews', $selfReviews);
8893        $this->set('selfLessonCount', $selfLessonCount);
8894        $this->set('daysPast', $daysPast);
8895        $this->set('meta_teacher_img',$_teacherImgUrl);
8896
8897        # get studydapuri textbooks
8898        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
8899        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
8900            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
8901            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
8902        } elseif ($this->isStudySapuriTosUser) {
8903            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
8904        } else {
8905            $exCat = Configure::read('all_sapuri_textbook_category_types');
8906            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
8907        }
8908
8909        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
8910
8911        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
8912        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
8913        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
8914        $lessonHistories = $this->getLessonHistory(true, $teacherId);
8915        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
8916
8917        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
8918        $coinParams =  array(
8919            'current_rank_id' => $teacherCurrentRankId,
8920            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
8921            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
8922            'student_native_option' => $userData->native_option,
8923            'home_flg' => $teacher->home_flg,
8924            'counseling_flg' => $teacher->counseling_flg,
8925            'avatar_parent_flg' => $teacher->avatar_parent_flg,
8926            'avatar_flg' => $teacher->avatar_flg,
8927            'native_speaker_flg' => $teacher->native_speaker_flg
8928        );
8929
8930        // get teacher coin settings
8931        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
8932        $teacherCoinData = [];
8933        if($teacherReserveCoin){
8934            // set teacher reservation coin
8935            $teacherCoinData = [
8936                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
8937                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
8938                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
8939                'reserve_coin_with_op' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
8940                'displayNativeOptionAmountFlg' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
8941                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
8942                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
8943            ];
8944            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
8945            $teacherCoinData['callan_coin'] = (int) $callanCoin;
8946            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
8947
8948            $sapuriCoin = 0;
8949            if ($this->isStudySapuriUser) {
8950                $teacherParams = array(
8951                    'teacher_id' => $teacher->id,
8952                    'current_rank_id' => $teacherCurrentRankId
8953                );
8954                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
8955            }
8956
8957        }
8958
8959        $OS = myTools::getOSFromUA($_SERVER['HTTP_USER_AGENT'], TRUE);
8960
8961        // NJ-20069 - feature tag lists
8962        $feature_tags_list = [
8963            "new" => "新人講師",
8964            "best_free_talk" => "フリートークが得意",
8965            "good_in_teaching_textbook" => "教材レッスンが得意",
8966            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
8967            "have_many_beginner_students" => "初級者向き",
8968            "suitable_for_children" => "キッズ向き",
8969            "suitable_for_senior" => "シニア向き",
8970            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
8971            "good_for_first_timer" => "体験レッスン向き",
8972            "pronunciation" => "発音"
8973        ];
8974        $data = $this->User->findById($userId);
8975
8976        // NJ-17264
8977        $titleThresholdData = [];
8978
8979        $this->TitleThresholdTeacher->openDBReplica();
8980        $titleThresholdData = $this->TitleThresholdTeacher->find('first', [
8981            'fields'=>'TitleThresholdTeacher.title_type',
8982            'conditions' => array(
8983                'TitleThresholdTeacher.teacher_id' => $teacherId,
8984                'TitleThresholdTeacher.type = 1'
8985            ),
8986            'recursive' => -1
8987        ]);
8988        $this->TitleThresholdTeacher->closeDBReplica();
8989        // NJ-17264
8990
8991        $this->set('user',$data);
8992        $this->set('userOS', $OS);
8993        $this->set('localizeDir', $this->localizeDir);
8994        $this->set('teacherCoinData', $teacherCoinData);
8995        $this->set('lessonHistories', $lessonHistories);
8996        $this->set('teacherRates', $reserveAndCancel);
8997        $this->set('teacherOccupation', $teacherOccupation);
8998        $this->set('series', $return['series']);
8999        $this->set('feature', $return['feature']);
9000        $this->set('historyMonth', $historyMonth);
9001        $this->set('historyYear', $historyYear);
9002        $this->set('weekly_ratings', $get_weekly_rating['TeacherWeeklyRating']);
9003        $this->set('teacherId', $teacherId);
9004        $this->set('feature_tags_list', $feature_tags_list);
9005        $this->set('features', $this->teacherFeatures(true, $teacherId));
9006        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9007        $this->set('favoriteCount', $favoriteCount);
9008        $this->set('sapuriCoin', $sapuriCoin);
9009        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9010        $this->set('title_type', isset($titleThresholdData['TitleThresholdTeacher']['title_type']) ? $titleThresholdData['TitleThresholdTeacher']['title_type'] : 0);
9011
9012        $this->layout = 'mobile';
9013        $this->render('/Mobile/Teacher/detail');
9014    }
9015
9016
9017    //Retrieves the details of a specific avatar teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9018    public function spAvatarDetail($teacherId) {
9019        if (!intval($teacherId)) {
9020            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9021        }
9022
9023        //fetch teacher data
9024        $data = $this->Teacher->findById($teacherId);
9025
9026        //no teacher data
9027        if (!$data) {
9028            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9029        }
9030
9031        // //check company ip and if the teacher is stealth on redirect to teacher list
9032        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
9033        //     $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
9034        // }
9035
9036        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9037            return $this->redirect('/waiting');
9038        }
9039
9040        //lesson onair
9041        $onair1 = $this->LessonOnair->find('first', array(
9042            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
9043            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
9044            ));
9045
9046        //number of reservation
9047
9048        //teacher_status if login or break
9049        $teacherStatus1 = $this->TeacherStatus->find('first', array(
9050            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
9051            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
9052            );
9053        // get counrty details
9054        $teacherCountryDetails = $this->CountryCode->find('first', array(
9055            'fields' => array('country_name', 'nationality', 'code'),
9056            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
9057            );
9058
9059        //get own reviews
9060        $selfReviews = array();
9061        $selfLessonCount = 0;
9062        $selfLessonNow = 0;
9063        $selfReservation = 0;
9064        $daysPast = 0;
9065        $userId = $this->Auth->user('id');
9066        if ($userId) {
9067            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
9068            $selfReviews = $this->getUserReviews($userId, $teacherId);
9069            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9070            $selfLessonNow = $userLessonDetail['lessonCount'];
9071            $selfReservation = $userLessonDetail['reserveCount'];
9072            $selfLessonCount = $selfLessonNow + $selfReservation;
9073            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9074        }
9075
9076        if (!empty($onair1)) {
9077            $onair = new LessonOnairTable($onair1['LessonOnair']);
9078        } elseif (!empty($teacherStatus1)) {
9079            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9080        } else {
9081            $onair = 0;
9082        }
9083
9084
9085        $this->set('onair', $onair);
9086        $this->set('teacher_id', $teacherId);
9087
9088        $teacher = new TeacherTable($data['Teacher']);
9089        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
9090        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9091        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
9092        $this->set('teacher', $teacher);
9093
9094        # get weekly rating
9095        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
9096        //number of lesson
9097        $lessonCount = (int)$teacher->lesson_count;
9098
9099        //number of lesson for all child accounts
9100        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9101
9102        // Translate and save translated data
9103        $globalTranslate = TeacherTable::translate(array(
9104            'id' => $teacher->id,
9105            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
9106            'controller' => static::class
9107        ));
9108        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
9109        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
9110        $this->set('message', $translatedMessageTranslation);
9111        $this->set('intro', $translatedThirdppTranslation);
9112
9113        // - prepare head text
9114        $headTextWD = $pageTitleWD  = $teacher->name;
9115        $metaDescWD = "";
9116
9117        //find the selfintro 
9118        $TeacherTable = new TeacherTable($teacher);
9119        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
9120        $_userSelfIntro = strip_tags($_userSelfIntro); 
9121
9122        if ($this->localizeDir == Configure::read('default.user_language')) {
9123            $headTextWD .= '('.$teacher->jp_name.')';
9124            $pageTitleWD .=  '('.$teacher->jp_name.')';
9125            //$metaDescWD .= '('.$teacher->jp_name.')';
9126        }
9127        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
9128        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
9129        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
9130        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
9131
9132        //prepare meta image 
9133        $_teacherImgUrl = $teacher->getImageUrl();
9134
9135        //check if teacher has no image 
9136        if (empty($teacher->image_url) || !$teacher->image_url) {
9137            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9138            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9139        }
9140
9141
9142        // - set page meta information
9143        $this->set('headtext', $headTextWD);
9144        $this->set('title_for_layout', $pageTitleWD);
9145        $this->set('meta_description', $metaDescWD);
9146        $this->set('lessonCount', $lessonCount);
9147        $this->set('country', $country);
9148        //$this->set('rateBreakdown', $rateBreakdown);
9149        $this->set('selfReviews', $selfReviews);
9150        $this->set('selfLessonCount', $selfLessonCount);
9151        $this->set('daysPast', $daysPast);
9152        $this->set('meta_teacher_img',$_teacherImgUrl);
9153    
9154
9155        # get studydapuri textbooks
9156        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
9157        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
9158            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
9159            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
9160        } elseif ($this->isStudySapuriTosUser) {
9161            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
9162        } else {
9163            $exCat = Configure::read('all_sapuri_textbook_category_types');
9164            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
9165        }
9166        
9167        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
9168
9169        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9170        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9171        $lessonHistories = $this->getLessonHistory(true, $teacherId);
9172        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
9173
9174        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
9175
9176        // get user data
9177        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9178
9179        $coinParams =  array(
9180            'current_rank_id' => $teacherCurrentRankId,
9181            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9182            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9183            'student_native_option' => $userData['native_option'],
9184            'home_flg' => $teacher->home_flg,
9185            'counseling_flg' => $teacher->counseling_flg,
9186            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9187            'avatar_flg' => $teacher->avatar_flg,
9188            'native_speaker_flg' => $teacher->native_speaker_flg
9189        );
9190
9191        // get teacher coin settings
9192        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
9193        $teacherCoinData = [];
9194        if($teacherReserveCoin){
9195            // set teacher reservation coin
9196            $teacherCoinData = [
9197                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
9198                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
9199                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
9200                'displayNativeOptionAmountFlg' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
9201                'reserve_coin_with_op' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
9202                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
9203                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
9204            ];
9205            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
9206            $teacherCoinData['callan_coin'] = (int) $callanCoin;
9207
9208            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9209
9210            $sapuriCoin = 0;
9211            if ($this->isStudySapuriUser) {
9212                $teacherParams = array(
9213                    'teacher_id' => $teacher->id,
9214                    'current_rank_id' => $teacherCurrentRankId
9215                );
9216                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
9217            }
9218
9219        }
9220        
9221        // NJ-42412 - added feature also to spAvatarDetail (Related to NJ-20069)
9222        $feature_tags_list = [
9223            "new" => "新人講師",
9224            "best_free_talk" => "フリートークが得意",
9225            "good_in_teaching_textbook" => "教材レッスンが得意",
9226            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
9227            "have_many_beginner_students" => "初級者向き",
9228            "suitable_for_children" => "キッズ向き",
9229            "suitable_for_senior" => "シニア向き",
9230            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
9231            "good_for_first_timer" => "体験レッスン向き",
9232            "pronunciation" => "発音"
9233        ];
9234        $this->set('teacherCoinData', $teacherCoinData);
9235        $this->set('lessonHistories', $lessonHistories);
9236        $this->set('teacherRates', $reserveAndCancel);
9237        $this->set('series', $return['series']);
9238        $this->set('features', json_encode((array)$return['feature']));
9239        $this->set('historyMonth', $historyMonth);
9240        $this->set('historyYear', $historyYear);
9241        $this->set('weekly_ratings', isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0);
9242        $this->set('teacherId', $teacherId);
9243        $this->set('avatarId', $this->isAvatar($teacherId));
9244        $this->set('favoriteCount', $favoriteCount);
9245        $this->set('feature_tags_list', $feature_tags_list);
9246        $this->set('sapuriCoin', $sapuriCoin);
9247        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9248        $this->layout = 'mobile';
9249        $this->render('/Mobile/Teacher/avatar_detail');
9250    }
9251
9252    /**
9253     * @api {get} /user/:language/avatar_detail/:teacherId/:highLightFlag avatar_detail()
9254     * @apiName avatar_detail
9255     * @apiGroup Waiting
9256     * @apiDescription Retrieves the details of a specific avatar teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9257     *
9258     * @apiParam {String} language The language code for the page.
9259     * @apiParam {String} teacherId The ID of the avatar teacher.
9260     * @apiParam {Boolean} [highLightFlag] Indicates whether to highlight certain elements on the page.
9261     * 
9262     * @apiSuccess {Object} teacher The teacher information.
9263     * @apiSuccess {String} teacher.id The ID of the teacher.
9264     * @apiSuccess {String} teacher.name The name of the teacher.
9265     * @apiSuccess {String} teacher.jp_name The Japanese name of the teacher.
9266     * @apiSuccess {String} teacher.image_url The URL of the teacher's image.
9267     * @apiSuccess {Object} country The country information.
9268     * @apiSuccess {String} country.country_name The name of the country.
9269     * @apiSuccess {String} country.national The nationality.
9270     * @apiSuccess {Object} timezone The timezone information.
9271     * @apiSuccess {String} timezone.timezone The timezone.
9272     * @apiSuccess {Object} tutorCategory The tutor category information.
9273     * @apiSuccess {Number} tutorCategory.coins The number of coins the teacher has.
9274     * @apiSuccess {Number} tutorCategory.limited_plan_reservation Indicates whether the teacher has a limited plan reservation (0: No, 1: Yes).
9275     * @apiSuccess {Number} timeDiff The time difference between the user's local time and the teacher's time.
9276     * @apiSuccess {Object} onair The on-air lesson information.
9277     * @apiSuccess {Number} onair.status The status of the on-air lesson.
9278     * @apiSuccess {Number} onair.connect_flg Indicates whether the teacher is connected (1: Yes, 0: No).
9279     * @apiSuccess {Number} teacherCoin The coin amount for the teacher.
9280     * @apiSuccess {Number} callanCoin The Callan coin amount for the teacher.
9281     * @apiSuccess {Number} teacherCallanDiscount The Callan discount for the teacher.
9282     * @apiSuccess {Number} lessonCount The number of lessons the teacher has conducted.
9283     * @apiSuccess {Number} historyYear The number of years the teacher has been teaching.
9284     * @apiSuccess {Number} historyMonth The number of months the teacher has been teaching.
9285     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
9286     * @apiSuccess {String} keep_memo.memo The memo text.
9287     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown.
9288     * @apiSuccess {Number} reserveAndCancel.reserve The number of reservations.
9289     * @apiSuccess {Number} reserveAndCancel.cancel The number of cancellations.
9290     * @apiSuccess {Object} lessonHistory The lesson history of the teacher.
9291     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
9292     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the teacher.
9293     * @apiSuccess {Number} latestUserLesson.id The ID of the lesson.
9294     * @apiSuccess {Number} latestUserLesson.teacher_id The ID of the teacher.
9295     * @apiSuccess {Number} latestUserLesson.user_id The ID of the user.
9296     * @apiSuccess {Number} teacherFavoriteCount The count of users who have favorited the teacher.
9297     * @apiSuccess {Number} stusapLessonCount The count of Study Sapuri lessons conducted by the teacher.
9298     * @apiSuccess {Object[]} album The album of images for the teacher.
9299     * @apiSuccess {Number} album.id The ID of the image.
9300     * @apiSuccess {String} album.image_url The URL of the image.
9301     * @apiSuccess {Object} oOnair The on-air status of the teacher.
9302     * @apiSuccess {Number} oOnair.status The status of the on-air lesson.
9303     * @apiSuccess {String} oOnair.remarks1 Remarks about the on-air lesson.
9304     * @apiSuccess {Boolean} isFav Indicates whether the user has favorited the teacher.
9305     * @apiSuccess {Number} favoriteCount The count of users who have favorited the teacher.
9306     * @apiSuccess {Object} feature The features of the teacher.
9307     * @apiSuccess {Boolean} feature.new Indicates whether the teacher is new.
9308     * @apiSuccess {Boolean} feature.best_free_talk Indicates whether the teacher is best for free talk.
9309     * @apiSuccess {Boolean} feature.good_in_teaching_textbook Indicates whether the teacher is good in teaching textbooks.
9310     * @apiSuccess {Boolean} feature.suitable_for_intermediate_or_advance_students Indicates whether the teacher is suitable for intermediate or advanced students.
9311     * @apiSuccess {Boolean} feature.have_many_beginner_students Indicates whether the teacher has many beginner students.
9312     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
9313     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
9314     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
9315     * @apiSuccess {String} reservationTextbookConnectId The ID of the textbook connect for the reservation.
9316     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates whether to hide the limited plan reservation.
9317     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates whether it is the user's first time logging in.
9318     * @apiSuccess {Number} velifyCount The count of phone verification checks.
9319     * @apiSuccess {Object[]} countryCodes The list of country codes.
9320     * @apiSuccess {String} countryCodes.country_name The name of the country.
9321     * @apiSuccess {String} countryCodes.nationality The nationality.
9322     * @apiSuccess {String} countryCodes.code The country code.
9323     * @apiSuccess {Object} userCountry The country information of the user.
9324     * @apiSuccess {String} userCountry.country_name The name of the country.
9325     * @apiSuccess {String} userCountry.national The nationality.
9326     * @apiSuccess {String} userCountry.code The country code.
9327     * @apiSuccess {Boolean} paidParent Indicates whether the user is a paid parent.
9328     * @apiSuccess {String} headtext The head text for the page.
9329     * @apiSuccess {String} title_for_layout The title for the page layout.
9330     * @apiSuccess {String} meta_description The meta description for the page.
9331     * @apiSuccess {String} meta_keywords The meta keywords for the page.
9332     * @apiSuccess {String} meta_teacher_img The URL of the teacher's image for meta tags.
9333     * @apiSuccess {Object[]} selfReviews The self-reviews of the user for the teacher.
9334     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
9335     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
9336     * @apiSuccess {Object[]} reviews The reviews of the teacher.
9337     * @apiSuccess {Number} reviews.commentCount The count of comments for the teacher.
9338     * @apiSuccess {Number} reviews.approveEvalFlag The flag indicating the approval status of the evaluations.
9339     * @apiSuccess {Number} commentCount The count of comments for the teacher.
9340     * @apiSuccess {Number} approveEvalFlag The flag indicating the approval status of the evaluations.
9341     * @apiSuccess {Object} weekly_ratings The weekly ratings of the teacher.
9342     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.id The ID of the weekly rating.
9343     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.teacher_id The ID of the teacher.
9344     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.week The week of the rating.
9345     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.year The year of the rating.
9346     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.rating The rating.
9347     * @apiSuccess {Object} translatedMessageParams The translated message parameters.
9348     * @apiSuccess {String} translatedMessageParams.translatedMessage The translated message.
9349     * @apiSuccess {Object} translatedSelfIntroductionThirdPpParams The translated self-introduction parameters.
9350     * @apiSuccess {String} translatedSelfIntroductionThirdPpParams.translatedSelfIntroductionThirdPp The translated self-introduction.
9351     * @apiSuccess {Object} translationModel The translation model.
9352     * @apiSuccess {Number} translationModel.id The ID of the translation.
9353     * @apiSuccess {Number} translationModel.teacher_id The ID of the teacher.
9354     * @apiSuccess {String} translationModel.lang The language of the translation.
9355     * @apiSuccess {String} translationModel.controller The controller of the translation.
9356     * @apiSuccess {Number} teacherCoinBeforeDiscount The coin amount for the teacher before discount.
9357     * @apiSuccess {Number} teacherCoinWithOp The coin amount for the teacher with options.
9358     * @apiSuccess {Boolean} nativeOptionFlg Indicates whether the native option is enabled.
9359     * @apiSuccess {Object} preset The preset textbook information.
9360     * @apiSuccess {String} preset.textbookConnectId The ID of the textbook connect.
9361     * @apiSuccess {String} preset.textbookCategoryTypeId The type ID of the textbook category.
9362     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
9363     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
9364     * @apiSuccess {Object[]} apologyList The list of apologies for reservation cancellations.
9365     * @apiSuccess {Number} apologyList.id The ID of the apology.
9366     * @apiSuccess {String} apologyList.apology The apology text.
9367     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
9368     * @apiSuccess {Boolean} disabledSchedule.disabled Indicates whether the schedule is disabled.
9369     * @apiSuccess {Boolean} showNoticeMaxLimit Indicates whether to show the notice for the maximum limit.
9370     * @apiSuccess {Boolean} noIndexFlgOveride Indicates whether to override the no-index flag.
9371     * @apiSuccess {Boolean} enableNextTextbookChapterButton Indicates whether to enable the next textbook chapter button.
9372     * @apiSuccess {String} chatHash The chat hash for the lesson.
9373     * @apiSuccess {Number} lessonRequestFlg The flag indicating the lesson request status.
9374     *
9375     * @apiSuccessExample {json} Success-Response:
9376     *     {
9377     *         "teacher": {
9378     *             "id": 520,
9379     *             "name": "Teacher Name",
9380     *             "jp_name": "Teacher Name",
9381     *             "image_url": "http://example.com/image.jpg"
9382     *         },
9383     *         "country": {
9384     *             "country_name": "Country Name",
9385     *             "national": "National"
9386     *         },
9387     *         "timezone": {
9388     *             "timezone": "Asia/Tokyo"
9389     *         },
9390     *         "tutorCategory": {
9391     *             "coins": 100,
9392     *             "limited_plan_reservation": 0
9393     *         },
9394     *         "timeDiff": 32400,
9395     *         "onair": {
9396     *             "status": 1,
9397     *             "connect_flg": 1
9398     *         },
9399     *         "teacherCoin": 100,
9400     *         "callanCoin": 50,
9401     *         "teacherCallanDiscount": 20,
9402     *         "lessonCount": 10,
9403     *         "historyYear": 2,
9404     *         "historyMonth": 3,
9405     *         "keep_memo": {
9406     *             "memo": "Memo"
9407     *         },
9408     *         "reserveAndCancel": {
9409     *             "reserve": 5,
9410     *             "cancel": 2
9411     *         },
9412     *         "lessonHistory": {},
9413     *         "lessonHistoryCount": 5,
9414     *         "latestUserLesson": {
9415     *             "id": 123,
9416     *             "teacher_id": 520,
9417     *             "user_id": 456
9418     *         },
9419     *         "teacherFavoriteCount": 100,
9420     *         "stusapLessonCount": 50,
9421     *         "album": [
9422     *             {
9423     *                 "id": 1,
9424     *                 "image_url": "http://example.com/image1.jpg"
9425     *             }
9426     *         ],
9427     *         "oOnair": {
9428     *             "status": 1,
9429     *             "remarks1": "Remarks"
9430     *         },
9431     *         "isFav": true,
9432     *         "favoriteCount": 200,
9433     *         "feature": {
9434     *             "new": true,
9435     *             "best_free_talk": true,
9436     *             "good_in_teaching_textbook": true,
9437     *             "suitable_for_intermediate_or_advance_students": true,
9438     *             "have_many_beginner_students": true
9439     *         },
9440     *         "isHide": false,
9441     *         "unsupportedBrowser": false,
9442     *         "canReport": true,
9443     *         "reservationTextbookConnectId": "123",
9444     *         "hideLimitedPlanReservation": false,
9445     *         "firstTimeLoggedIn": true,
9446     *         "velifyCount": 1,
9447     *         "countryCodes": [
9448     *             {
9449     *                 "country_name": "Country Name",
9450     *                 "nationality": "National",
9451     *                 "code": "Code"
9452     *             }
9453     *         ],
9454     *         "userCountry": {
9455     *             "country_name": "Country Name",
9456     *             "national": "National",
9457     *             "code": "Code"
9458     *         },
9459     *         "paidParent": false,
9460     *         "headtext": "Teacher Name",
9461     *         "title_for_layout": "Teacher Name - 講師詳細 | オンライン英会話のネイティブキャンプ",
9462     *         "meta_description": "Teacher description",
9463     *         "meta_keywords": "Teacher Name,講師,オンライン英会話,ネイティブキャンプ",
9464     *         "meta_teacher_img": "http://example.com/image.jpg",
9465     *         "selfReviews": [...],
9466     *         "selfLessonCount": 5,
9467     *         "daysPast": 10,
9468     *         "reviews": [
9469     *             {
9470     *                 "commentCount": 50,
9471     *                 "approveEvalFlag": 1
9472     *             }
9473     *         ],
9474     *         "commentCount": 50,
9475     *         "approveEvalFlag": 1,
9476     *         "weekly_ratings": {
9477     *             "TeacherWeeklyRating": {
9478     *                 "id": 123,
9479     *                 "teacher_id": 520,
9480     *                 "week": 1,
9481     *                 "year": 2021,
9482     *                 "rating": 5
9483     *             }
9484     *         },
9485     *         "translatedMessageParams": {
9486     *             "translatedMessage": "Translated message"
9487     *         },
9488     *         "translatedSelfIntroductionThirdPpParams": {
9489     *             "translatedSelfIntroductionThirdPp": "Translated self-introduction"
9490     *         },
9491     *         "translationModel": {
9492     *             "id": 123,
9493     *             "teacher_id": 520,
9494     *             "lang": "en",
9495     *             "controller": "WaitingController"
9496     *         },
9497     *         "teacherCoinBeforeDiscount": 120,
9498     *         "teacherCoinWithOp": 130,
9499     *         "nativeOptionFlg": true,
9500     *         "preset": {
9501     *             "textbookConnectId": "456",
9502     *             "textbookCategoryTypeId": "789"
9503     *         },
9504     *         "textbookConnectId": "456",
9505     *         "textbookCategoryTypeId": "789",
9506     *         "apologyList": [
9507     *             {
9508     *                 "id": 1,
9509     *                 "apology": "Apology"
9510     *             }
9511     *         ],
9512     *         "disabledSchedule": {
9513     *             "disabled": true
9514     *         },
9515     *         "showNoticeMaxLimit": false,
9516     *         "noIndexFlgOveride": false,
9517     *         "enableNextTextbookChapterButton": true,
9518     *         "chatHash": "example_chat_hash",
9519     *         "lessonRequestFlg": 1
9520     *     }
9521     *
9522     * @apiError {String} error Message indicating the error.
9523     *
9524     * @apiErrorExample {json} Error-Response:
9525     *     {
9526     *         "error": "Invalid request."
9527     *     }
9528     * 
9529     * @apiSampleRequest off
9530     */
9531    public function avatar_detail($teacherId = 520, $highLightFlag = null) {
9532        if (is_null($teacherId)) {
9533            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
9534        }
9535
9536        $this->avatarLatestLessonHistory($this->Auth->user('id'), $teacherId);
9537        //set mobile view
9538        if (myTools::defaultAction($this)) {
9539            return $this->spAvatarDetail($teacherId);
9540        }
9541
9542        $checkParams = array(
9543            'type' => 'count',
9544            'args' => array(
9545                'conditions' => array(
9546                    'id' => $teacherId,
9547                    'avatar_parent_flg' => 0
9548                ),
9549                'recursive' => -1
9550            )
9551        );
9552
9553        // - NC-3802: redirect to mypage if not avatar parent teacher
9554        if ($this->Teacher->getTeachers($checkParams)) {
9555            return $this->redirect('/mypage');
9556        }
9557
9558        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9559            return $this->redirect('/waiting');
9560        }
9561        //redirect to proper profile
9562        $this->checkProperProfile($teacherId);
9563
9564        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
9565        $queryCondition = array(
9566            'fields' => array(
9567                    'TeacherRankCoin.coins',
9568                    'LessonOnair.id',
9569                    'LessonOnair.teacher_id',
9570                    'LessonOnair.user_id',
9571                    'TeacherRankCoin.limited_plan_reservation'
9572                ),
9573            'joins' => array(
9574                array(
9575                    'type' => 'LEFT',
9576                    'table' => 'teacher_rank_coins',
9577                    'alias' => 'TeacherRankCoin',
9578                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
9579                )
9580            ),
9581            'conditions' => array(
9582                array('Teacher.id' => $teacherId)
9583            ),
9584            'show' => 'first'
9585        );
9586
9587        $commonTeacherStatusParams = array(
9588            'page_display' => 'listTeacher',
9589            'query_conditions' => $queryCondition
9590        );
9591        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
9592
9593        if (!$data) {
9594            return $this->redirect('/waiting/');
9595        }
9596
9597        //redirect if withdrawn teacher or teacher is block in NJ-43859
9598        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1 || in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
9599            if ($this->Auth->loggedIn()) {
9600                return $this->redirect(myTools::geturl() . '/mypage');
9601            } else {
9602                return $this->redirect(myTools::geturl() . '/waiting');
9603            }
9604        }
9605
9606        if (isset($data['LessonOnair'])) {
9607            $tmp = (object) $data['LessonOnair'];
9608            if (!$tmp->id) {
9609                $data['LessonOnair'] = null;
9610            }
9611        }
9612
9613
9614
9615        // get teacher information
9616        $teacher = new TeacherTable($data['Teacher']);
9617
9618        $country = new TeacherTable($data['CountryCode']);
9619        $timezone = new TimezoneTable($data['Timezone']);
9620        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9621
9622        // Avatar var
9623        $avatarTeacherId = $teacherId;
9624        $teacherName = isset($teacher->jp_name) ? $teacher->jp_name : null;
9625        $teacherNameEn = isset($teacher->name) ? $teacher->name : null;
9626        $teacherImageSrc = $teacher->getImageUrl();
9627
9628        $timeDiff = 0;
9629        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
9630            $timeDiffData = $this->Timezone->computeTimeDiff(array(
9631                'continent_id' => $timezone->continent_id,
9632                'city' => $timezone->city_eng
9633            ));
9634
9635            //
9636            if ($timeDiffData['success']) {
9637                $timeDiff = $timeDiffData['timeDiff'];
9638            }
9639        }
9640
9641        $onair = $data['LessonOnair'];
9642
9643        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9644        # Get teachers reservation amounts.
9645        $req_params =  array(
9646                'basic_amount_type' => 15,
9647                'current_rank_id' => $teacherCurrentRankId
9648            );
9649        $teacherCoin = $this->HomeBasedRankBasicAmountLog->getBasicAmount($req_params);
9650
9651        //
9652        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9653
9654        // get user data
9655        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9656
9657        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
9658        $coinParams =  array(
9659            'current_rank_id' => $teacherCurrentRankId,
9660            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9661            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9662            'student_native_option' => $userData['native_option'],
9663            'home_flg' => $teacher->home_flg,
9664            'counseling_flg' => $teacher->counseling_flg,
9665            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9666            'avatar_flg' => $teacher->avatar_flg,
9667            'native_speaker_flg' => $teacher->native_speaker_flg
9668        );
9669
9670        // get teacher coin settings
9671        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
9672
9673        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
9674        $displayNativeOptionAmountFlg = false;
9675        if($teacherCoinData){
9676            // set teacher reservation coin
9677            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
9678            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
9679            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
9680            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
9681        }
9682
9683        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
9684
9685        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9686
9687        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
9688
9689        //number of lesson
9690        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9691
9692        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9693
9694        $this->set('historyMonth',$historyMonth);
9695        $this->set('historyYear',$historyYear);
9696
9697        //NJ-20069 avatar detail changes
9698        $getKeepMemo = $this->UsersMemo->find('first', array(
9699            'fields' => array(
9700                'id',
9701                'memo'
9702            ),
9703            'conditions' => array(
9704                'user_id' => $this->Auth->user('id'),
9705                'teacher_id' => $teacherId,
9706                'type' => 0
9707            ),
9708            'order' => array('created DESC'),
9709        ));
9710
9711        $this->set('keep_memo', $getKeepMemo);
9712
9713        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9714        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null, "avatar");
9715        $lessonHistoryCount  = is_iterable(($lessonHistory['lessonHistory'])) ? count($lessonHistory['lessonHistory']) : 0;
9716        $latestUserLesson = ($lessonHistory['lessonHistory'][0]['LessonOnairsLog']);
9717        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
9718        $stusapLessonCount = $this->Teacher->getAvatarSapuriLessonCount($teacherId);
9719
9720        // - if has translated Category name
9721        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
9722            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
9723        }
9724
9725        $formattedLatestLessonData = "";
9726        if(!empty($latestUserLesson))
9727        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
9728
9729        $this->set('lessonHistoryCount', $lessonHistoryCount);
9730        $this->set('latestUserLesson', $lessonHistory['lessonHistory'][0]);
9731        $this->set('teacherRates', $reserveAndCancel);
9732        $this->set('teacherIdCheck', $teacherId);
9733        $this->set('latestLessonData', $formattedLatestLessonData);
9734        $this->set('lessonHistory', $lessonHistory);
9735        $this->set('teacherId', $teacherId);
9736        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
9737        $this->set('stusapLessonCount', $stusapLessonCount);
9738        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9739
9740
9741
9742        // album
9743        $this->TeacherImage->openDBReplica();
9744        $album = $this->TeacherImage->find('all', array(
9745            'fields' => array(
9746                'TeacherImage.id',
9747                'TeacherImage.teacher_id',
9748                'TeacherImage.approve_flg',
9749                'TeacherImage.is_profile',
9750                'TeacherImage.approve_required',
9751                'FileStorage.url'
9752            ),
9753            'conditions' => array(
9754                'TeacherImage.teacher_id' => $teacherId,
9755                'TeacherImage.is_profile' => 0,
9756                'OR' => array(
9757                    'OR' => array(
9758                            'TeacherImage.approve_flg' => 1,
9759                            'TeacherImage.approve_required' => 0
9760                        )
9761                    )
9762            ),
9763            'joins' => array(
9764                array(
9765                    'type' => 'INNER',
9766                    'table' => 'file_storage',
9767                    'alias' => 'FileStorage',
9768                    'conditions' => array(
9769                        'TeacherImage.file_storage_id = FileStorage.id',
9770                        'FileStorage.uploader_type = 3',
9771                        'FileStorage.uploader_id' => $teacherId
9772                    )
9773                )
9774            ),
9775            'order' => array('TeacherImage.id DESC')
9776        ));
9777        $this->TeacherImage->closeDBReplica();
9778
9779        $this->set('album', $album);
9780
9781        //lesson onair
9782        if (!empty($onair)) {
9783            $oOnair = new LessonOnairTable($onair);
9784        } else {
9785            //teacher_status if login or break
9786            $teacherStatus1 = $this->TeacherStatus->find('first', array(
9787                'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
9788                'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
9789            ));
9790            if (!empty($teacherStatus1)) {
9791                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9792            } else {
9793                $oOnair = 0;
9794            }
9795        }
9796
9797        //favorite
9798        $where = array(
9799            'UsersFavorite.user_id'     => $this->Auth->user('id'),
9800            'UsersFavorite.teacher_id'     => $teacherId,
9801        );
9802        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
9803        $where = array(
9804            'UsersFavorite.teacher_id'  => $teacherId,
9805        );
9806        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
9807        $where = array(
9808            'TeacherFeature.teacher_id' => $teacherId,
9809        );
9810        $feature = $this->TeacherFeature->find('first', array('conditions' => $where));
9811
9812        // NC-5897 : check if teacher was hide by user.
9813        $where = array(
9814            'user_id' => $this->Auth->user('id'),
9815            'teacher_id' => $teacherId,
9816        );
9817        $isHide = $this->BlockList->isTeacherHide($where);
9818
9819        $feature = isset($feature['TeacherFeature']) ? new TeacherFeatureTable($feature['TeacherFeature']) : new TeacherFeatureTable(array());
9820        $this->User->recursive = -1;
9821        $data = $this->User->findById($userId);
9822        $user = isset($data['User'])?$data['User']: null;
9823        $unsupportedBrowser = false;
9824        $browser =  $this->request->header('User-Agent');
9825
9826        if (preg_match('/(Edg|Edge)/i',$browser) ) {
9827            $unsupportedBrowser = false;
9828        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
9829            $unsupportedBrowser = true;
9830        }
9831        $canReport = true;
9832        $reservationTextbookConnectId = "";
9833        if ($user) {
9834            $userData = new UserTable($data['User']);
9835            $userMembership = $userData->getUserMembership();
9836            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
9837            $this->set('user_lang', $userData->native_language2);
9838            // if weekly plan user
9839            $corporateUser = isset($corporateType) ? $corporateType : '';
9840
9841            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
9842            $canReport = $userData->getMembershipTypeIndex();
9843            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
9844            //NJ-24096: get last reservation textbook type
9845            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true :false;
9846            $lastReservationData = LessonScheduleTable::getLastReservation($userId, $sapuriFlg);
9847
9848            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
9849                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
9850            } else {
9851                $this->User->openDBReplica();
9852                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
9853                $this->User->closeDBReplica();
9854                if (empty($checkUserFirstFlg)) {
9855                    $defaultParams = array(
9856                        'user_id' => $userId,
9857                        'lang' => $userData->native_language2
9858                    );
9859                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
9860                    if ($defaultReservation) {
9861                        $reservationTextbookConnectId = $defaultReservation;
9862                    }
9863                }
9864            }
9865        }
9866        $this->set(compact('reservationTextbookConnectId'));
9867        $this->set('unsupportedBrowser', $unsupportedBrowser);
9868        // NC-6615 check if user can report the teacher
9869        $this->set('canReport', $canReport);
9870
9871        $hideLimitedPlanReservation = false;
9872        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
9873            $hideLimitedPlanReservation = true;
9874        }
9875
9876        $firstTimeLoggedIn = false;
9877        if (!$user['last_login_time']) {
9878            $firstTimeLoggedIn = true;
9879        }
9880
9881        $paidParent = false;
9882
9883        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
9884            'conditions' => array(
9885                'user_id' => $this->Auth->user('id'),
9886                'status' => 0
9887            )
9888        ));
9889
9890        $countryCodes = $this->CountryCode->find('all',array(
9891            'fields' => array(
9892                'code',
9893                'country_name'
9894            ),
9895            'order' => 'country_name ASC'
9896        ));
9897        $this->set('countryCodes',$countryCodes);
9898
9899        $userCountry['CountryCode']['country_name'] = '';
9900        $userCountry['CountryCode']['code'] = '';
9901        if(!empty($data['User']['country_code'])){
9902            $userCountry = $this->CountryCode->find('first',array(
9903                'conditions' => array(
9904                    'code' => $data['User']['country_code']),
9905                'fields' => array(
9906                    'code',
9907                    'country_name')
9908            ));
9909            if(empty($userCountry)){
9910                $userCountry['CountryCode']['code'] = '';
9911            }
9912        }
9913        $this->set('countryCodes',$countryCodes);
9914
9915        //check if user is child by checking its parent id not empty
9916        if (isset($data['User']['parent_id'])) {
9917            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
9918        }
9919        #$lesson_count=0;
9920        // 管理者権限会員は無制限でレッスン出来る
9921        if ($user['admin_flg']=='1') {
9922            $user['charge_flg'] = 1;
9923            $lesson_count=0;
9924            $lesson_count_today = 0;
9925        }
9926
9927        if (empty($user['enquate6'])) {
9928            $user['enquate6'] = '1';
9929        }
9930
9931        if (empty($user['enquate7'])) {
9932            $user['enquate7'] = '1';
9933        }
9934        // - prepare head text
9935        $headTextWD = $pageTitleWD = $teacherNameEn;
9936        $metaDescWD = "";
9937        if ($this->localizeDir == Configure::read('default.user_language')) {
9938            $headTextWD .= '('.$teacherName.')';
9939            $pageTitleWD .=  '('.$teacherName.')';
9940            //$metaDescWD .= '('.$teacherName.')';
9941        }
9942        $pageTitleWD .= '&ensp;-&ensp;'. __d('default_pc','講師詳細 | オンライン英会話のネイティブキャンプ');
9943        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
9944
9945        //prepare meta image 
9946        $_teacherImgUrl = $teacher->getImageUrl();
9947
9948        //check if teacher has no image 
9949        if (empty($teacher->image_url) || !$teacher->image_url) {
9950            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9951            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9952        }
9953
9954        // - set page meta information
9955        $this->set('headtext', $headTextWD);
9956        $this->set('title_for_layout', $pageTitleWD);
9957        //$this->set('meta_description', $metaDescWD);
9958        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
9959        $this->set('counselingFlg',$teacher->counseling_flg);
9960        $this->set('meta_teacher_img',$_teacherImgUrl);
9961        //get own reviews
9962        $selfReviews = array();
9963        $selfLessonCount = 0;
9964        $daysPast = 0;
9965        if ($userId) {
9966            $selfReviews = $this->getUserReviews($userId, $teacherId);
9967            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9968            $selfLessonNow = $userLessonDetail['lessonCount'];
9969            $selfReservation = $userLessonDetail['reserveCount'];
9970            $selfLessonCount = $selfLessonNow + $selfReservation;
9971            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9972        }
9973        //reservation and cancellation breakdown
9974        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9975
9976        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
9977        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
9978        $options['language_id'] = $reviewLanguage[0];
9979        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
9980        $options['avatar'] = 1;
9981
9982        $userTable = new UserTable($this->Auth->user());
9983        $sapuriPlan = $userTable->isStudySapuri();
9984        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
9985        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
9986            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
9987        } else {
9988            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
9989        }
9990
9991        $reviews = $this->UsersClassEvaluation->getComments($teacherId, 0, 4, $options);
9992        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
9993        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
9994
9995        # get weekly rating
9996        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
9997
9998        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
9999        
10000        /* -- NC-5293 start -- */
10001        $this->loadModel('Translation');
10002        $translationCategories = Configure::read('translation_categories');
10003        $translateParams = array(
10004            'languageCode' => $this->lang_iso,
10005            'categoryId' => $translationCategories['teacher_message'],
10006            'messageId' => $teacher->id,
10007            'text' => $teacher->message
10008        );
10009
10010        $translatedMessageParams = $translateParams;
10011        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
10012        $translateParams['text'] = $teacher->self_introduction_third_pp;
10013        $translatedSelfIntroductionThirdPpParams = $translateParams;
10014        /* -- NC-5293 end -- */
10015
10016        // Translate and save translated data
10017        $globalTranslate = TeacherTable::translate(array(
10018            'id' => $teacherId,
10019            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
10020            'controller' => static::class
10021        ));
10022        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
10023        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
10024        $this->set('message', $translatedMessageTranslation);
10025        $this->set('intro', $translatedThirdppTranslation);
10026
10027        //find the selfintro 
10028        $TeacherTable = new TeacherTable($teacher);
10029        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
10030        $_userSelfIntro = strip_tags($_userSelfIntro);
10031
10032        //set the new meta description
10033        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
10034        $this->set('meta_description', $metaDescWD);
10035    
10036        $favIds = $isFav ? [$teacher->id] : [];
10037        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
10038        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
10039            'favIds' => $favIds,
10040            'favIdsTeacherCategory' => $teacherFavColor
10041        ]);
10042        // set view vars
10043        $setData = array(
10044            'teacher' => $teacher,
10045            'onair' => $oOnair,
10046            'isFav' => $isFav,
10047            'teacherFavsColors' => $teacherFavsColors,
10048            'isHide' => $isHide,
10049            'favoriteCount' => $favoriteCount,
10050            'feature' => $feature,
10051            'tId' => $teacher->id,
10052            'user' => $user,
10053            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
10054            'userMembership' => isset($userMembership)?$userMembership:'',
10055            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
10056            'enquate6_options' => UserTable::getEnquate6(),
10057            'enquate7_options' => UserTable::getEnquate7(),
10058            'reviews' => $reviews,
10059            //'rates' => $rates,
10060            'approveEvalFlag' => $approveFlag,
10061            'weekly_ratings' => isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
10062            'userId' => $userId,
10063            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
10064            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
10065            'callanCoin' => (int)$callanCoin,
10066            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
10067            'UserData' => $data,
10068            'userCountry' => $userCountry,
10069            'velifyCount' => $velifyCount,
10070            'firstTimeLoggedIn' => $firstTimeLoggedIn,
10071            //'rateBreakdown' => $rateBreakdown,
10072            'selfReviews' => $selfReviews,
10073            'selfLessonCount' => $selfLessonCount,
10074            'daysPast' => $daysPast,
10075            'reserveAndCancel' => $reserveAndCancel,
10076            'isLoggedIn' => $this->Auth->loggedIn(),
10077            'country' => $country,
10078            'timeDiff' => $timeDiff,
10079            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
10080            'translatedMessageParams' => $translatedMessageParams,
10081            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
10082            'translationModel' => $this->Translation,
10083            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
10084            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
10085            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
10086            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
10087            'lessonCount' => $lessonCount,
10088        );
10089
10090        $this->set($setData);
10091        $this->set('avatar_teacher_detail', 1);
10092        if ($userId) {
10093            $points = $this->UsersPoint->find('first', array(
10094                'fields' => array('point'),
10095                    'conditions' => array(
10096                        'user_id' => $userId
10097                    )
10098                )
10099            );
10100
10101            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
10102            $reservePoint = Configure::read("reserve_point");
10103
10104            if (intval($reservePoint) < 1) $reservePoint = 0;
10105            //set promo discount for reservation
10106            // set paramater to 2 for reservation promo
10107            $bonus = CoinSetTable::getCoinSet(2);
10108            //check if the promo is valid today
10109            if ($bonus) {
10110                $reservePoint = $bonus;
10111            }
10112        } else {
10113            $points = 0;
10114        }
10115
10116        # get user timezone
10117        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
10118        $user_timezone_data = $this->Timezone->find('first',
10119            array(
10120                'fields' => array(
10121                    'Timezone.city_eng',
10122                    'Timezone.utc_offset',
10123                    'Timezone.country_code_id'
10124                ),
10125                'conditions' => array(
10126                    'Timezone.id' => $user_timezone_id
10127                ),
10128                'recursive' => -1
10129            )
10130        );
10131
10132        // - NJ-3653 get country
10133        $countryTimezone = null;
10134        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
10135            // - Get all country Code
10136            $countryOptions = $this->Timezone->countryOptions();
10137
10138            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
10139            $countryName = $countryOptions[$countryCodeId]['country_name'];
10140
10141            if (isset($countryName) && $countryName) {
10142                $countryTimezone = $countryName;
10143            }
10144        }
10145
10146
10147        $this->set('countryTimezone', $countryTimezone);
10148        $this->set('userTimezoneData', $user_timezone_data);
10149
10150        #user time
10151        $datetime = date('Y-m-d H:i:s');
10152        $localTime = $this->displayTime;
10153        // NJ-29496
10154        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
10155            $formattedDate = date('d/m/Y G:i', $localTime);
10156        } else {
10157            $formattedDate = date('Y/m/d G:i', $localTime);
10158        }
10159    
10160        $this->set('userCurrentTime', $formattedDate);        
10161
10162        $this->set('points', $points);
10163        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
10164
10165        $countrids_no = Configure::read('sms_send.countrids_no');
10166        $this->set('countrids_no', $countrids_no);
10167
10168        $deviceNotSupported = false;
10169        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
10170        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
10171            $deviceNotSupported = true;
10172        }
10173        $this->set('deviceNotSupported', $deviceNotSupported);
10174
10175        $this->set('statusCheck', array(1, 4));
10176
10177        $this->set('login', $this->Auth->loggedIn());
10178
10179        //get preset textbook -> last viewed -> default textbook category first lesson
10180        $presetParams = array("user_id" => $this->Auth->User('id'));
10181
10182        //add additional parameters
10183        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
10184            $presetParams["lang"] = $this->localizeDir;
10185        }
10186        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
10187        $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
10188
10189        #NC-9916
10190        if($data['User']) {
10191            $presetParams['native_language2'] = $userData->native_language2;
10192            $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
10193        }
10194        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
10195
10196        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
10197            # for preset
10198            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
10199            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10200
10201        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
10202            # use last viewed textbook if no preset data.
10203            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
10204            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10205
10206        }
10207
10208        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
10209        $presetParams['is_pc_flg'] = 1;
10210
10211        # fetch preset
10212        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10213        if(!$preset) {
10214            unset($presetParams['connect_id']);
10215            unset($presetParams['last_opened_date']);
10216            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10217        }
10218
10219        // NC-8020
10220        $this->set('textbookConnectId', $preset['textbook_connect_id']);
10221        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
10222
10223        //set variable preset textbook to be displayed
10224        $this->set('preset', $preset);
10225        // apology list (cancellation of reservation)
10226         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
10227        $this->set('apologyList', $apologyList);
10228
10229        $getAvatarParams = array(
10230            "avatar_id" => $teacherId,
10231            "user_id" => $this->Auth->user('id'),
10232            "stealth_flg" => $this->Cookie->read('stealth.setting')
10233        );
10234        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
10235
10236        // NJ-18780 : check if user is normal lite plan
10237        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
10238        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
10239
10240
10241        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
10242            'userId' => $this->Auth->user('id'),
10243            'teacherId' => $avatarTeacherIds,
10244            'timeDiff' => $this->timeDiff,
10245            'isNormalLitePlanUser' => $isNormalLitePlanUser
10246        ));
10247
10248        // dynamic techer
10249
10250        $avatarParams = array(
10251            "user_id" => $this->Auth->user('id'),
10252            "avatar_id" => $teacherId
10253        );
10254
10255        $avatarTeacherArr = $this->Avatar->availableTeacher($avatarParams);
10256        $lessTime = 0;
10257        if ( isset($avatarTeacherArr["teacher_id"]) ) {
10258            $avatarTeacherId = $avatarTeacherArr["teacher_id"];
10259        }
10260        if ( isset($avatarTeacherArr["less_time"]) ) {
10261            $lessTime = $avatarTeacherArr["less_time"];
10262        }
10263        $options['isAvatar'] = 1;
10264        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
10265
10266        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
10267        $this->set('reviewsCount', $reviewsCount);
10268        $this->set('teacherName', $teacherName);
10269        $this->set('teacherImageSrc', $teacherImageSrc);
10270        $this->set('lessTime', $lessTime);
10271        $this->set('isAvatar',true);
10272        $this->set('avatarTeacherId', $avatarTeacherId);
10273        $this->set('disabledSchedule', json_encode($disabledSchedule));
10274        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
10275        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
10276
10277        // - NJ-6390 add highLightFlag
10278        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
10279
10280        // class evaluation
10281        if ($this->request->query('chatHash')) {
10282            $chatHash = $this->request->query('chatHash');
10283
10284            // Check if chatHash is valid
10285            $this->LessonOnairsLog->openDBReplica();
10286            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
10287            $this->LessonOnairsLog->closeDBReplica();
10288
10289            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
10290                $this->LessonOnair->openDBReplica();
10291                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
10292                $this->LessonOnair->closeDBReplica();
10293
10294                if(!$allData) {
10295                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
10296                }
10297            }
10298
10299            $userValidForSSBEDT = false;
10300            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
10301                $userValidForSSBEDT = true;
10302            }
10303            $param = array(
10304                "user_id" => $userId,
10305                "select_method" => "first",
10306                "env_flag" => "all",
10307                'connect_id' => $allData['Connect']['id'],
10308                "user_locale" => $this->localizeDir,
10309                "userValidForSSBEDT" => $userValidForSSBEDT
10310            );
10311            
10312            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
10313                $corporateParams = array('user_id' => $userId);
10314                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10315                
10316                if ($corporateTextbookControlFlg == 1) {
10317                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
10318                    if (!empty($categoryData)) {
10319                        $param['include_kids_category'] = $allData['Connect']['category_id'];
10320                    }
10321                }
10322            }
10323            $textbookData = $this->Textbook->getTextbooks($param);
10324            $data = $textbookData['res_data'];
10325
10326            $isReservedLesson = 2;
10327            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
10328            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
10329            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
10330            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
10331            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
10332
10333            //Optimize PC /lesson-finish page
10334            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
10335            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
10336                $lessonOnairLatestDataFlg = true;
10337                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
10338                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
10339            } else {
10340                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
10341                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
10342                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
10343                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
10344                }
10345            }
10346
10347            // - initialize empty variable
10348            $isLatestPresetTextbookMadeDuringLastLesson = [];
10349            $latestPresetTextbookParams = [];
10350
10351            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
10352            if ($lessonOnairLatestDataFlg) {
10353                $latestPresetTextbookParams = array (
10354                    'userId' => $userId,
10355                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10356                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
10357                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
10358                );
10359
10360            // - if has lesson onairs log
10361            } else if ($lessonOnairLogsLatestData) {
10362                $latestPresetTextbookParams = array (
10363                    'userId' => $userId,
10364                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10365                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
10366                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
10367                );
10368
10369            }
10370            
10371            // - if has parameters for fetching latest textbook parameters
10372            if ($latestPresetTextbookParams) {
10373                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
10374            }
10375
10376            // -  check sapuri ID
10377            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
10378                if (isset($lessonOnairLatestDataFlg)) {
10379                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10380                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
10381                    ) {
10382                        $hideTextbookChangeModal = 'true';
10383                    }
10384                } else {
10385                    if (
10386                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10387                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
10388                    ) {
10389                        $hideTextbookChangeModal = 'true';
10390                    }
10391                }
10392            }
10393
10394            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
10395
10396            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
10397            if (
10398                $hideTextbookChangeModal == 'false'
10399                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
10400                && (isset($onGoingLesson) && $onGoingLesson == false)
10401            ) {
10402                $allTextbookParams = array(
10403                    'category_id' => $latestPresetTextbookConnect_categoryId, 
10404                    'connect_id' => $latestPresetTextbookConnect_id,
10405                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
10406                );
10407                
10408                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
10409                // if has next textbook chapter, show button 
10410                if (
10411                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
10412                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
10413                ) {
10414                    $enableNextTextbookChapterButton = 'true';
10415                }
10416            }
10417
10418            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
10419
10420            if(!empty($this->sharedUserData['User'])){
10421                // - campaing stamps
10422                $this->getActiveCampaignStampData();
10423            }
10424
10425            $this->set('chatHash', $chatHash);
10426        }
10427
10428        //NJ-33414
10429        $this->UsersDetail->openDBReplica();
10430        $fetchUsersDetail = $this->UsersDetail->find('first', array(
10431            'fields' => array(
10432                'lesson_request_flg'
10433            ),
10434            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
10435            'recursive' => -1
10436        ));
10437        $this->UsersDetail->closeDBReplica();
10438
10439        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
10440        $this->set('lessonRequestFlg',$lessonRequestFlg);
10441
10442        //-- NJ-44869 skip communication modal
10443        $lessonSystemTroubleFlg = 0;
10444        $hideConnectionModalFlg = 0;
10445
10446        // if (!empty($chatHash)) {
10447        //     $memcached = new myMemcached();
10448        //     $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
10449        //     $lessonDisconnectionChatHash = $memcached->get('lesson_disconnection_flag_' . $teacherId);
10450            
10451        //     $hideConnectionModalFlg = $memcached->get('hide_connection_modal_flg_'.$teacherId.'-'.$chatHash);
10452
10453        //     if (!empty($lessonSystemTroubleCache)) {
10454        //         $memcached->delete('lesson_system_trouble_' . $chatHash);
10455        //         $lessonSystemTroubleFlg = 1;
10456        //     } elseif (!empty($lessonDisconnectionChatHash) && $lessonDisconnectionChatHash == $chatHash) {
10457        //         $lessonSystemTroubleFlg = 1;
10458        //     }
10459        // }
10460
10461        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
10462        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
10463    }
10464
10465    /**
10466     * @api {get} /user/waiting/getTeacherReviews getTeacherReviews()
10467     * @apiName getTeacherReviews
10468     * @apiGroup Waiting
10469     * @apiDescription Retrieves the reviews for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reviews data.
10470     *
10471     * @apiBody {String} [teacherId] The ID of the teacher.
10472     * @apiBody {Boolean} [isCounseling] Indicates whether the request is for a counseling teacher.
10473     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10474     * @apiBody {Boolean} [isCustomerSupport] Indicates whether the request is for a customer support teacher.
10475     * @apiBody {Number} [order] The order of the reviews.
10476     * @apiBody {Number} [limit=4] The limit of reviews to retrieve.
10477     * @apiBody {Number} [page=1] The current page number.
10478     * @apiBody {Number} [rate] The rating filter for the reviews.
10479     * @apiBody {String} [textbook_course] The textbook course filter for the reviews.
10480     * @apiBody {String} [textbook_series] The textbook series filter for the reviews.
10481     * @apiBody {String} [textbook_preset] The textbook preset filter for the reviews.
10482     * @apiBody {String} [textbook_favorite] The textbook favorite filter for the reviews.
10483     * @apiBody {Boolean} [load_categories] Indicates whether to load the textbook categories.
10484     * @apiBody {Boolean} [load_paging] Indicates whether to load the paging data.
10485     * 
10486     * @apiSuccess {String} htmlReviews The HTML content for the reviews.
10487     * @apiSuccess {Number} counselorReviewsCount The count of counselor reviews.
10488     * @apiSuccess {String} htmlPaging The HTML content for the paging data.
10489     * @apiSuccess {Object[]} textbookCategories The textbook categories data.
10490     * @apiSuccess {String} textbookCategories.id The ID of the textbook category.
10491     * @apiSuccess {String} textbookCategories.name The name of the textbook category.
10492     * @apiSuccess {String} textbookCategories.image The image URL of the textbook category.
10493     *
10494     * @apiSuccessExample {json} Success-Response:
10495     *     {
10496     *         "htmlReviews": "<div>Reviews HTML</div>",
10497     *         "counselorReviewsCount": 10,
10498     *         "htmlPaging": "<div>Paging HTML</div>",
10499     *         "textbookCategories": [
10500     *             {
10501     *                 "id": "1",
10502     *                 "name": "Category Name",
10503     *                 "image": "http://example.com/image.jpg"
10504     *             },
10505     *             ...
10506     *         ]
10507     *     }
10508     *
10509     * @apiError {String} error Message indicating the error.
10510     *
10511     * @apiErrorExample {json} Error-Response:
10512     *     {
10513     *         "error": "Invalid request."
10514     *     }
10515     * 
10516     * @apiSampleRequest off
10517     */
10518    public function getTeacherReviews() {
10519        $this->autoRender = $this->layout = false;
10520        $get = $this->request->query;
10521
10522        if (isset($get['teacherId']) && !filter_var($get['teacherId'], FILTER_VALIDATE_INT)) {
10523            return json_encode([]);
10524        }
10525
10526        $counselorReviewsCount = 0;
10527        if (isset($get['teacherId']) || isset($get['isCounseling']) || isset($get['isAvatar']) || isset($get['isCustomerSupport'])) {
10528            if (isset($get['order'])) {
10529                $this->Cookie->write('teacherReviewOrder', $get['order'], true, 0);
10530            }
10531            $order = $this->Cookie->read('teacherReviewOrder') ?? 0;
10532            $limit = !empty($get['limit']) && is_numeric($get['limit']) ? (int) $get['limit'] : 4;
10533            $page  = !empty($get['page'])  && is_numeric($get['page'])  ? (int) $get['page']  : 1;
10534            $params = array(
10535                'order' => $order,
10536                'limit' => $limit,
10537                'offset' => ($page - 1) * $limit,
10538                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10539                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10540                'lang' => $this->localizeDir
10541            );
10542
10543            // office teacher
10544            if ( isset($get['isCounseling']) || isset($get['isCustomerSupport']) ) {
10545                myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
10546                $teachersReviews = new TeachersCounselorReviewsController();
10547                $teachersReviews->params = $params;
10548                $isCustomerSupport = isset($get['isCustomerSupport']) ? true : false;
10549                $reviews = $teachersReviews->getAllCounselEvaluation($isCustomerSupport);
10550                $counselorReviewsCount = $teachersReviews->getCountAllEvaluation($isCustomerSupport);
10551            } else {
10552                myTools::initializeApiTunnel(array('TeachersReviewsController'));
10553                $teachersReviews = new TeachersReviewsController();
10554                $params['conditions'] = array();
10555                if(isset($get['isAvatar'])) {
10556                    if(!isset($get['load_categories'])) {
10557                        $params['conditions'][] = "UsersClassEvaluation.teacher_id IN (SELECT id FROM teachers WHERE avatar_id = {$get['teacherId']} AND status = 1)";
10558                        $params['conditions'][] = "UsersClassEvaluation.approve_flag = 1";
10559                        $params['conditions'][] = "UsersClassEvaluation.user_comment <> ''";
10560                    }
10561                    $params['isAvatar'] = true;
10562                    $params['avatarTeacherId'] = $get['teacherId'];
10563                } else {
10564                    $params['conditions']['UsersClassEvaluation.teacher_id'] = $get['teacherId'];
10565                }
10566
10567                $params['rate'] = $get['rate'] ?? null;
10568                $params['textbook_course'] = $get['textbook_course'] ?? null;
10569                $params['textbook_series'] = $get['textbook_series'] ?? null;
10570                $params['textbook_preset'] = $get['textbook_preset'] ?? null;
10571                $params['textbook_favorite'] = $get['textbook_favorite'] ?? null;
10572                $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10573
10574
10575                $userTable = new UserTable($this->Auth->user());
10576                $sapuriPlan = $userTable->isStudySapuri();
10577                $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10578                if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10579                    $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10580                } else {
10581                    $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10582                }
10583
10584                if ($userId = $this->Auth->user('id')) {
10585                    $corporateParams = array('user_id' => $userId);
10586                    $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10587                    
10588                    if ($corporateTextbookControlFlg == 1) {
10589                        $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10590                    }
10591                }
10592
10593                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10594                $params['build_conditions']['language_id'] = $reviewLanguage[0];
10595                $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10596                
10597                $teachersReviews->params = $params;
10598                $reviews = $teachersReviews->getReviews();
10599
10600                if (isset($get['load_categories'])) {
10601                    $teachersReviews->params['load_favorite'] = true;
10602                    $teachersReviews->params['isLoadCategories'] = true;
10603                    $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10604                }
10605            }
10606            if ($reviews) {
10607                $view = new View($this, false);
10608                $htmlReviews = $view->element('teacherReviews', array('reviews' => $reviews));
10609
10610                if (isset($get['load_paging'])) {
10611                    $commentCount = $this->UsersClassEvaluation->useReplica()->countTeacherReviews($teachersReviews->convertOldParams($params), true);
10612                    $paging = myTools::paging($page, $commentCount, $limit);
10613                    $htmlPaging = $view->element('pager_link_instructor_reviews_ng', ['paging' => $paging, 'order' => $order]);
10614                }
10615            }
10616        }
10617
10618        $returnArr = array();
10619        if (isset($htmlReviews)) {
10620            $returnArr['htmlReviews'] = $htmlReviews;
10621            $returnArr['counselorReviewsCount'] = $counselorReviewsCount;
10622        }
10623        if (isset($htmlPaging)) {
10624            $returnArr['htmlPaging'] = $htmlPaging;
10625        }
10626        if(isset($textbookCategories)) {
10627            $returnArr['textbookCategories'] = $textbookCategories;
10628        }
10629
10630        return json_encode($returnArr);
10631    }
10632
10633    /**
10634     * @api {post} /user/waiting/favoriteTextbookCategoryForReview favoriteTextbookCategoryForReview()
10635     * @apiName favoriteTextbookCategoryForReview
10636     * @apiGroup Waiting
10637     * @apiDescription Retrieves the favorite textbook categories for review for the authenticated user in Native Camp. It returns the favorite textbook categories data.
10638     *
10639     * @apiBody {String} [lang=ja] The language code for the request.
10640     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10641     * @apiBody {String} [teacherId] The ID of the teacher.
10642     * 
10643     * @apiSuccess {Object[]} favorite The favorite textbook categories data.
10644     * @apiSuccess {String} favorite.id The ID of the textbook category.
10645     * @apiSuccess {String} favorite.name The name of the textbook category.
10646     * @apiSuccess {String} favorite.image The image URL of the textbook category.
10647     *
10648     * @apiSuccessExample {json} Success-Response:
10649     *     {
10650     *         "favorite": [
10651     *             {
10652     *                 "id": "1",
10653     *                 "name": "Category Name",
10654     *                 "image": "http://example.com/image.jpg"
10655     *             },
10656     *             ...
10657     *         ]
10658     *     }
10659     *
10660     * @apiError {String} error Message indicating the error.
10661     *
10662     * @apiErrorExample {json} Error-Response:
10663     *     {
10664     *         "error": "Invalid request."
10665     *     }
10666     * 
10667     * @apiSampleRequest off
10668     */
10669    public function favoriteTextbookCategoryForReview() {
10670        $this->autoRender = false;
10671        $result = [];
10672        if (isset($this->request->data) ) {
10673            $inputs = $this->request->data;
10674            $lang = 'ja';
10675            if (isset($inputs['lang']) && !empty($inputs['lang'])) $lang = $inputs['lang'];
10676            $this->localizeDir = $lang;
10677
10678            myTools::initializeApiTunnel(array('TeachersReviewsController'));
10679            $teachersReviews = new TeachersReviewsController();
10680            $params = array(
10681                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10682                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10683                'lang' => $this->localizeDir
10684            );
10685            $params['conditions'] = array();
10686
10687            if( isset($inputs['isAvatar']) && $inputs['isAvatar'] ) {
10688                $params['isAvatar'] = true;
10689                $params['isLoadCategories'] = true;
10690            } else {
10691                $params['conditions']['UsersClassEvaluation.approve_flag'] = 1;
10692                $params['conditions']['UsersClassEvaluation.user_comment <>'] = '';
10693                $params['conditions']['UsersClassEvaluation.teacher_id'] = $inputs['teacherId'];
10694            }
10695            $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10696
10697            $userTable = new UserTable($this->Auth->user());
10698            $sapuriPlan = $userTable->isStudySapuri();
10699            $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10700
10701            if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10702                $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10703            } else {
10704                $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10705            }
10706
10707            if ($userId = $this->Auth->user('id')) {
10708                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl(['user_id' => $userId]);
10709                if ($corporateTextbookControlFlg == 1) {
10710                    $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10711                }
10712            }
10713
10714            $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10715            $params['build_conditions']['language_id'] = $reviewLanguage[0];
10716            $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10717            $params['load_favorite'] = true;
10718            $teachersReviews->params = $params;
10719
10720            $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10721            $result = !empty($textbookCategories) && isset($textbookCategories['favorite']) ? $textbookCategories['favorite'] : [];
10722        }
10723        return json_encode($result);
10724    }
10725
10726    /**
10727     * @api {post} /user/waiting/teacherAvatarStatus teacherAvatarStatus()
10728     * @apiName teacherAvatarStatus
10729     * @apiGroup Waiting
10730     * @apiDescription Retrieves the status of avatar teachers for the authenticated user in Native Camp. It checks the availability of the specified avatar teachers and returns their status.
10731     *
10732     * @apiBody {String[]} avatar_id_array The array of avatar teacher IDs.
10733     * 
10734     * @apiSuccess {Object} result The status of the avatar teachers.
10735     * @apiSuccess {Object} result.avatarId The status data for the avatar teacher.
10736     * @apiSuccess {Boolean} result.avatarId.available Indicates whether the avatar teacher is available.
10737     * @apiSuccess {String} result.avatarId.status The status of the avatar teacher.
10738     *
10739     * @apiSuccessExample {json} Success-Response:
10740     *     {
10741     *         "123": {
10742     *             "available": true,
10743     *             "status": "online"
10744     *         },
10745     *         "456": {
10746     *             "available": false,
10747     *             "status": "offline"
10748     *         }
10749     *     }
10750     *
10751     * @apiError {String} error Message indicating the error.
10752     *
10753     * @apiErrorExample {json} Error-Response:
10754     *     {
10755     *         "error": "Invalid request."
10756     *     }
10757     * 
10758     * @apiSampleRequest off
10759     */
10760    public function teacherAvatarStatus() {
10761        $this->autoRender = $this->layout = false;
10762        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : '';
10763        $post = $this->request->data;
10764        $avatarIdArr = array_flip(Configure::read("default_avatar_detail"));
10765        $result = array();
10766
10767        if(isset($post["avatar_id_array"]) && is_array($post["avatar_id_array"]) ) {
10768            foreach ($post["avatar_id_array"] as $key => $avatarId) {
10769
10770                    $params = array(
10771                        "user_id" => $userId,
10772                        "avatar_id" => $avatarId
10773                    );
10774                    $data = $this->Avatar->availableTeacher($params);
10775                    $result[$avatarId] = $data;
10776
10777
10778            }
10779
10780        }
10781
10782        return json_encode($result);
10783
10784    }
10785
10786    /**
10787     * @api {get} /user/waiting/checkMaintenanceForAlert checkMaintenanceForAlert()
10788     * @apiName checkMaintenanceForAlert
10789     * @apiGroup Waiting
10790     * @apiDescription Checks if there is an upcoming maintenance period and returns an alert message if maintenance is scheduled.
10791     *
10792     * @apiSuccess {Number} is_maintenance Indicates whether maintenance is scheduled (0: No, 1: Yes).
10793     * @apiSuccess {String} message The maintenance alert message.
10794     * @apiSuccess {Number} [timezone_id] The ID of the user's timezone (if applicable).
10795     *
10796     * @apiSuccessExample {json} Success-Response:
10797     *     {
10798     *         "is_maintenance": 1,
10799     *         "message": "2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。",
10800     *         "timezone_id": 1
10801     *     }
10802     *
10803     * @apiError {String} error Message indicating the error.
10804     *
10805     * @apiErrorExample {json} Error-Response:
10806     *     {
10807     *         "error": "Invalid request."
10808     *     }
10809     * 
10810     * @apiSampleRequest off
10811     */
10812    public function checkMaintenanceForAlert() {
10813        $this->autoRender = $this->layout = false;
10814        $response = array(
10815            'is_maintenance' => 0,
10816            'message' => __d('waiting','2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。')
10817        );
10818        if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR'])) {
10819            $conditions = array(
10820                'is_active' => 1,
10821                'start_date <= DATE_ADD(NOW(), INTERVAL 26 MINUTE)',
10822                'end_date >= NOW()'
10823            );
10824            $maintenanceModel = ClassRegistry::init('Maintenance');
10825            $maintenanceModel->openDBReplica();
10826            $maintenance = $maintenanceModel->find('first',array(
10827                'conditions' => $conditions
10828            ));
10829            $maintenanceModel->closeDBReplica();
10830            if ($maintenance) {
10831                $response['is_maintenance'] = 1;
10832                # maintenance time on user side
10833                if ($this->sharedUserData['User']['timezone_id']) {
10834                    $response['timezone_id'] = $this->sharedUserData['User']['timezone_id'];
10835                    $timezones = $this->Timezone->getFormattedRecruitTimezones();
10836                    $userTimeZoneData = $timezones[$this->sharedUserData['User']['timezone_id']];
10837                    $datetime = date($maintenance['Maintenance']['start_date']); // maintenance time
10838                    $timestamp = strtotime($datetime);
10839                    $fromTime = $timestamp + (($userTimeZoneData['jp_time_diff'] / 60) * 60 * 60);
10840                    $userMaintenanceTime = date("g:iA", $fromTime);
10841                    $uData = $this->Timezone->getTimezoneUserData($this->sharedUserData['User']['timezone_id']);
10842                    $alertMessageTime = $userMaintenanceTime. " (UTC".$uData['Timezone']['utc_offset'].") " .$userTimeZoneData['data-timezone_name'];
10843                    $alertMessage = sprintf(__d('waiting','%s より定期メンテナンスを行います。時間になりましたらレッスンも終了しますのでご了承ください。'), $alertMessageTime);
10844                    $response['message'] = $alertMessage;
10845                }
10846            }
10847        }
10848        echo json_encode($response);
10849    }
10850
10851    private function isAvatar($teacherID=null){
10852        $result = null;
10853        if ($teacherID) {
10854            $get = $this->Teacher->useReplica()->find('first',array(
10855                    'conditions' => array( 'Teacher.id' => $teacherID ),
10856                    'fields' => array(
10857                        'Teacher.id',
10858                        'Teacher.avatar_id',
10859                        'Teacher.avatar_parent_flg',
10860                        'Teacher.avatar_flg'
10861                    ),
10862                    'recursive' => -1
10863                )
10864            );
10865            if ($get) {
10866                // check parent
10867                $avatarParent = isset($get['Teacher']['avatar_parent_flg']) && $get['Teacher']['avatar_parent_flg'] ? $get['Teacher']['avatar_parent_flg'] : 0;
10868                $avatar = isset($get['Teacher']['avatar_flg']) && $get['Teacher']['avatar_flg'] ? $get['Teacher']['avatar_flg'] : 0;
10869                $avatarId = isset($get['Teacher']['avatar_id']) && $get['Teacher']['avatar_id'] ? $get['Teacher']['avatar_id'] : 0;
10870
10871                if ( ( $avatar && $avatarId ) || $avatarParent ) {
10872                    if ( $avatar && $avatarId ) {
10873                        $result = $avatarId;
10874                    }
10875                    if ($avatarParent) {
10876                        $result = $teacherID;
10877                    }
10878                }
10879            }
10880        }
10881        return $result;
10882    }
10883
10884
10885
10886    //Retrieves the latest lesson history for a specific user with counselor teachers in Native Camp. It returns the lesson history data.
10887    public function counselorLatestLessonHistory($userId){
10888
10889        $memcache = new myMemcached();
10890        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
10891
10892        $counselorTeacherId =  Configure::read('default_counselor_detail');
10893        //NC-7984
10894        $lessonHistoryJoins = array(
10895            "use index (user_id)",
10896            array(
10897                'type' => 'LEFT',
10898                'table' => 'users_class_evaluations',
10899                'alias' => 'usersClassEvaluations',
10900                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
10901            ),
10902            array(
10903                'type' => 'LEFT',
10904                'table' => 'textbook_connects',
10905                'alias' => 'TextbookConnect',
10906                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
10907            ),
10908            array(
10909                'type' => 'LEFT',
10910                'table' => 'textbook_categories',
10911                'alias' => 'TextbookCategory',
10912                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
10913            ),
10914            array(
10915                'type' => 'LEFT',
10916                'table' => 'textbook_subcategories',
10917                'alias' => 'TextbookSubategory',
10918                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
10919            ),
10920            array(
10921                'type' => 'LEFT',
10922                'table' => 'textbooks',
10923                'alias' => 'Textbook',
10924                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
10925            ),
10926            array(
10927                'type' => 'LEFT',
10928                'table' => 'teachers',
10929                'alias' => 'Teacher',
10930                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
10931            ),
10932            array(
10933                'type' => 'LEFT',
10934                'table' => 'lesson_track_logs',
10935                'alias' => 'LessonTrackLogs',
10936                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
10937            )
10938        );
10939        $lessonHistoryFields = array(
10940            'LessonOnairsLog.id',
10941            'LessonOnairsLog.start_time',
10942            'LessonOnairsLog.end_time',
10943            'LessonOnairsLog.created', //Lesson Data / time
10944            'LessonOnairsLog.chat_hash',
10945            'LessonOnairsLog.lesson_memo',
10946            'LessonOnairsLog.lesson_memo_disp_flg',
10947            'LessonOnairsLog.connect_id',
10948            'LessonOnairsLog.display_message',
10949            'LessonOnairsLog.teacher_id',
10950            'TextbookConnect.id',
10951            'usersClassEvaluations.rate', //Lesson rate
10952            'TextbookCategory.name',
10953            'TextbookCategory.type_id',
10954            'TextbookSubategory.name',
10955            'Textbook.name',
10956            'Teacher.id',
10957            'LessonTrackLogs.lesson_number'
10958        );
10959        $this->Teacher->openDBReplica();
10960        $subQuery = $this->Teacher->find(
10961            'list',
10962            array(
10963                'fields'     => array('Teacher.id'),
10964                'table'      => 'teachers',
10965                'alias'      => 'Teacher',
10966                'conditions' => array(
10967                    'Teacher.counseling_flg' => 1,
10968                    'Teacher.status' => 1
10969                ),
10970                'recursive' => -1
10971            )
10972        );
10973        $this->Teacher->closeDBReplica();
10974
10975        $lessonHistoryConditions = array(
10976            'LessonOnairsLog.teacher_id IN' => $subQuery,
10977            'LessonOnairsLog.user_id' => $userId,
10978            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
10979        );
10980
10981        // - has localized directory
10982        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
10983            // - get the user's language id
10984            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
10985            if ($langId) {
10986
10987                $lessonHistoryJoins[] = array(
10988                    'type' => 'LEFT',
10989                    'table' => 'global_textbook_categories',
10990                    'alias' => 'GlobalTextbookCategory',
10991                    'conditions' => array(
10992                        'GlobalTextbookCategory.language_id' => $langId,
10993                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
10994                    )
10995                );
10996
10997                $lessonHistoryJoins[] = array(
10998                    'type' => 'LEFT',
10999                    'table' => 'global_textbook_subcategories',
11000                    'alias' => 'GlobalTextbookSubcategory',
11001                    'conditions' => array(
11002                        'GlobalTextbookSubcategory.language_id' => $langId,
11003                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11004                    )
11005                );
11006                $lessonHistoryJoins[] = array(
11007                    'type' => 'LEFT',
11008                    'table' => 'global_textbooks',
11009                    'alias' => 'GlobalTextbook',
11010                    'conditions' => array(
11011                        'GlobalTextbook.language_id' => $langId,
11012                        'GlobalTextbook.textbook_id = Textbook.id'
11013                    )
11014                );
11015                $this->LessonOnairsLog->virtualFields = array(
11016                    'gl_subcateg_name' => 'GlobalTextbookSubcategory.gl_name',
11017                    'gl_name' => 'GlobalTextbook.gl_name'
11018                );
11019                $lessonHistoryFields[] = 'gl_categ_name';
11020                $lessonHistoryFields[] = 'gl_subcateg_name';
11021                $lessonHistoryFields[] = 'gl_name';
11022            }
11023        }
11024
11025        // - get lesson history
11026        $this->LessonOnairsLog->openDBReplica();
11027        $latestLessonHistory = $this->LessonOnairsLog->find(
11028            'all',
11029            array(
11030                'joins' => $lessonHistoryJoins,
11031                'fields' => $lessonHistoryFields,
11032                'conditions' => $lessonHistoryConditions,
11033                'limit' => 10, //int
11034                'order' => 'LessonOnairsLog.start_time DESC'
11035            )
11036        );
11037        $this->LessonOnairsLog->closeDBReplica();
11038
11039        $this->set('lessonHistory', $latestLessonHistory);
11040        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11041        //NC-7984
11042    }
11043
11044
11045    //Retrieves the latest lesson history for a specific avatar teacher and user in Native Camp. It returns the lesson history data.
11046    public function avatarLatestLessonHistory($userId, $teacherId){
11047        $memcache = new myMemcached();
11048        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
11049        //NC-7984
11050        $lessonHistoryJoins = array(
11051            "use index (user_id)",
11052            array(
11053                'type' => 'LEFT',
11054                'table' => 'users_class_evaluations',
11055                'alias' => 'usersClassEvaluations',
11056                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
11057            ),
11058            array (
11059                'type' => 'LEFT',
11060                'table' => 'textbook_connects',
11061                'alias' => 'TextbookConnect',
11062                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
11063            ),
11064            array(
11065                'type' => 'LEFT',
11066                'table' => 'textbook_categories',
11067                'alias' => 'TextbookCategory',
11068                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
11069            ),
11070            array(
11071                'type' => 'LEFT',
11072                'table' => 'textbook_subcategories',
11073                'alias' => 'TextbookSubategory',
11074                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
11075            ),
11076            array(
11077                'type' => 'LEFT',
11078                'table' => 'textbooks',
11079                'alias' => 'Textbook',
11080                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
11081            ),
11082            array(
11083                'type' => 'LEFT',
11084                'table' => 'teachers',
11085                'alias' => 'Teacher',
11086                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
11087            ),
11088            array(
11089                'type' => 'LEFT',
11090                'table' => 'lesson_track_logs',
11091                'alias' => 'LessonTrackLogs',
11092                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
11093            )
11094        );
11095        $lessonHistoryFields = array(
11096            'LessonOnairsLog.id',
11097            'LessonOnairsLog.start_time',
11098            'LessonOnairsLog.end_time',
11099            'LessonOnairsLog.created', //Lesson Data / time
11100            'LessonOnairsLog.chat_hash',
11101            'LessonOnairsLog.lesson_memo',
11102            'LessonOnairsLog.lesson_memo_disp_flg',
11103            'LessonOnairsLog.connect_id',
11104            'LessonOnairsLog.display_message',
11105            'TextbookConnect.id',
11106            'usersClassEvaluations.rate', //Lesson rate
11107            'TextbookCategory.name',
11108            'TextbookCategory.type_id',
11109            'TextbookSubategory.name',
11110            'Textbook.name',
11111            'Teacher.id',
11112            'LessonTrackLogs.lesson_number'
11113        );
11114        $this->Teacher->openDBReplica();
11115        $subQuery = $this->Teacher->find(
11116            'list',
11117            array(
11118                'fields'     => array('Teacher.id'),
11119                'table'      => 'teachers',
11120                'alias'      => 'Teacher',
11121                'conditions' => array(
11122                    "(Teacher.avatar_flg = 1 AND Teacher.counseling_flg = 0 AND Teacher.status = 1 AND Teacher.avatar_id = {$teacherId}) || (Teacher.avatar_parent_flg = 1 AND Teacher.id = {$teacherId})"
11123                ),
11124                'recursive' => -1
11125            )
11126        );
11127        $this->Teacher->closeDBReplica();
11128
11129        $lessonHistoryConditions = array(
11130            'LessonOnairsLog.user_id' => $userId,
11131            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
11132        );
11133
11134        if(is_array($subQuery) && !empty($subQuery)){
11135            $lessonHistoryConditions['LessonOnairsLog.teacher_id IN'] = $subQuery;
11136        }
11137
11138        // - has localized directory
11139        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11140            // - get the user's language id
11141            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11142            if ($langId) {
11143
11144                $lessonHistoryJoins[] = array(
11145                    'type' => 'LEFT',
11146                    'table' => 'global_textbook_categories',
11147                    'alias' => 'GlobalTextbookCategory',
11148                    'conditions' => array(
11149                        'GlobalTextbookCategory.language_id' => $langId,
11150                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11151                    )
11152                );
11153
11154                $lessonHistoryJoins[] = array(
11155                    'type' => 'LEFT',
11156                    'table' => 'global_textbook_subcategories',
11157                    'alias' => 'GlobalTextbookSubcategory',
11158                    'conditions' => array(
11159                        'GlobalTextbookSubcategory.language_id' => $langId,
11160                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11161                    )
11162                );
11163                $lessonHistoryJoins[] = array(
11164                    'type' => 'LEFT',
11165                    'table' => 'global_textbooks',
11166                    'alias' => 'GlobalTextbook',
11167                    'conditions' => array(
11168                        'GlobalTextbook.language_id' => $langId,
11169                        'GlobalTextbook.textbook_id = Textbook.id'
11170                    )
11171                );
11172
11173                $lessonHistoryFields[] = 'GlobalTextbookCategory.gl_name';
11174                $lessonHistoryFields[] = 'GlobalTextbookSubcategory.gl_name';
11175                $lessonHistoryFields[] = 'GlobalTextbook.gl_name';
11176            }
11177        }
11178
11179        // - get lesson history
11180        $this->LessonOnairsLog->openDBReplica();
11181        $latestLessonHistory = $this->LessonOnairsLog->find(
11182            'all',
11183            array(
11184                'joins' => $lessonHistoryJoins,
11185                'fields' => $lessonHistoryFields,
11186                'conditions' => $lessonHistoryConditions,
11187                'limit' => 10, //int
11188                'order' => 'LessonOnairsLog.start_time DESC'
11189            )
11190        );
11191        $this->LessonOnairsLog->closeDBReplica();
11192
11193        $this->set('lessonHistory', $latestLessonHistory);
11194        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11195        //NC-7984
11196    }
11197
11198    private function userAvailPopularTeacher($params=array()){
11199        $result = false;
11200        if ( isset($params['user_id']) && isset($params['avatar_id']) ) {
11201            $userId = $params['user_id'];
11202            $avatarId = $params['avatar_id'];
11203
11204            $getTeacherAvatars = $this->Teacher->getAvatarTeacherId($params);
11205            if ($getTeacherAvatars) {
11206                $disconCancel = Configure::read('accounting.disconnection_cancellation_lesson_finish');
11207                // - check if has db replica
11208                $this->LessonOnairsLog->openDBReplica();
11209                $countLessons = $this->LessonOnairsLog->find('count', array(
11210                        'conditions' => array(
11211                        'LessonOnairsLog.user_id' => $userId,
11212                        'LessonOnairsLog.teacher_id' => array_values($getTeacherAvatars),
11213                        'LessonOnairsLog.start_time IS NOT NULL',
11214                        'LessonOnairsLog.end_time IS NOT NULL',
11215                        'LessonOnairsLog.connect_id IS NOT NULL',
11216                        'LessonOnairsLog.lesson_finish' => 1
11217                    ),
11218                    'recursive' => -1
11219                ));
11220                $this->LessonOnairsLog->closeDBReplica();
11221
11222                if ($countLessons < 1) {
11223                    $result = true;
11224                }
11225
11226            }
11227
11228        }
11229        return $result;
11230    }
11231
11232
11233    //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
11234    private function userValidForSSBEDT(){
11235        $userValidForSSBEDT = false;
11236        if (
11237              (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
11238              ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
11239        ){
11240            $userValidForSSBEDT = true;
11241        }
11242
11243        return $userValidForSSBEDT;
11244    }
11245
11246    /**
11247     * @api {post} /user/waiting/loadLiveLessonTeacher loadLiveLessonTeacher()
11248     * @apiName loadLiveLessonTeacher
11249     * @apiGroup Waiting
11250     * @apiDescription Retrieves the list of teachers available for live lessons in Native Camp. It checks if the request is an AJAX request and returns the list of live lesson teachers.
11251     *
11252     * @apiBody {Number} [current_page=1] The current page number.
11253     * @apiBody {Number} [limit] The limit of teachers to retrieve.
11254     * @apiBody {String} [local_timezone] The local timezone of the user.
11255     * @apiBody {Boolean} [isGuestViwer] Indicates whether the user is a guest viewer.
11256     * @apiBody {Boolean} [isMobile] Indicates whether the request is from a mobile device.
11257     * @apiBody {String} [template] The template to use for rendering the teacher list.
11258     * @apiBody {String} [token] The API token of the user.
11259     * 
11260     * @apiSuccess {Object[]} liveTeacherList The list of teachers available for live lessons.
11261     * @apiSuccess {String} liveTeacherList.name The teacher's name.
11262     * @apiSuccess {String} liveTeacherList.id The teacher's unique identifier.
11263     * @apiSuccess {String} liveTeacherList.profilePicture URL to the teacher's profile picture.
11264     * @apiSuccess {Boolean} ajaxDisplay Indicates if the request was made via AJAX.
11265     * @apiSuccess {Number} userJpTimeDiffSecond The time difference in seconds between the user's local time and Japan time.
11266     * @apiSuccess {Number} studentLessonPriorityTimeDelayInSeconds The delay in seconds for student lesson priority.
11267     * @apiSuccess {Object} teacherListLiveParameters The parameters for the live teacher list (if applicable).
11268     * @apiSuccess {String} teacherListLiveParameters.user_id The ID of the user.
11269     * @apiSuccess {String} teacherListLiveParameters.user_language The language of the user.
11270     * @apiSuccess {Boolean} teacherListLiveParameters.pc_view Indicates if the view is for PC.
11271     * @apiSuccess {Number} teacherListLiveParameters.page The current page number.
11272     * @apiSuccess {String} teacherListLiveParameters.template The template used for rendering the teacher list.
11273     * @apiSuccess {Boolean} teacherListLiveParameters.mobapp_view Indicates if the view is for mobile app.
11274     * @apiSuccess {Number} teacherListLiveParameters.limit The limit of teachers to retrieve.
11275     * @apiSuccess {Boolean} teacherListLiveParameters.isGuestViwer Indicates if the user is a guest viewer.
11276     * @apiSuccess {Boolean} teacherListLiveParameters.isMobile Indicates if the request is from a mobile device.
11277     *
11278     * @apiSuccessExample {json} Success-Response:
11279     *     {
11280     *         "liveTeacherList": [
11281     *             {
11282     *                 "name": "Teacher Name",
11283     *                 "id": "123456",
11284     *                 "profilePicture": "https://www.nativecamp.net/img/teacher/123456.jpg"
11285     *             },
11286     *             ...
11287     *         ],
11288     *         "ajaxDisplay": true,
11289     *         "userJpTimeDiffSecond": 32400,
11290     *         "studentLessonPriorityTimeDelayInSeconds": 60,
11291     *         "teacherListLiveParameters": {
11292     *             "user_id": "789",
11293     *             "user_language": "en",
11294     *             "pc_view": true,
11295     *             "page": 1,
11296     *             "template": "pc_usage",
11297     *             "mobapp_view": false,
11298     *             "limit": 10,
11299     *             "isGuestViwer": false,
11300     *             "isMobile": false
11301     *         }
11302     *     }
11303     *
11304     * @apiError {String} error Message indicating the error.
11305     *
11306     * @apiErrorExample {json} Error-Response:
11307     *     {
11308     *         "error": "Invalid request."
11309     *     }
11310     * 
11311     * @apiSampleRequest off
11312     */
11313    public function loadLiveLessonTeacher(){
11314        $data = $this->request->data;
11315        $liveTeacherList = array();
11316        $params = array();
11317        $currentPage = !empty($data['current_page']) ? $data['current_page'] : 1 ;
11318        $limit = isset($data['limit']) ? $data['limit'] : null;
11319        $userJpTimeDiffSecond = !empty($this->timeDiffSecond) ? $this->timeDiffSecond : 0;
11320        $isGuestViwer = !empty($data['isGuestViwer']) ? 1 : 0;
11321
11322        //- if token set
11323        if (!empty($this->request->query['token'])) {
11324            $this->User->openDBReplica();
11325            $this->sharedUserData = $this->User->find('first', [
11326                'conditions' => ['api_token' => $this->request->query['token']],
11327                'recursive' => -1
11328            ]);
11329            $this->User->closeDBReplica();
11330
11331        }
11332
11333        //-- get JP time difference for logout users
11334        if (
11335            (empty($this->sharedUserData['User']) || $isGuestViwer)
11336            && !empty($data['local_timezone'])
11337            && $data['local_timezone'] != 'Asia/Tokyo'
11338        ) {
11339            $localTimezoneName = explode('/', $data['local_timezone']);
11340            if ( !empty($localTimezoneName[1]) ) {
11341                $this->Timezone->openDBReplica();
11342                $jpTimeDiff = $this->Timezone->find('first', array(
11343                    'fields' => 'jp_time_diff',
11344                    'conditions' => array(
11345                        'Timezone.city_eng LIKE ? ' => array($localTimezoneName[1])
11346                    ),
11347                    'recursive' => -1
11348                ));
11349                $this->Timezone->closeDBReplica();
11350                $userJpTimeDiffSecond = !empty($jpTimeDiff['Timezone']['jp_time_diff']) ? ((int)$jpTimeDiff['Timezone']['jp_time_diff'] * 60) : $userJpTimeDiffSecond;
11351            }
11352        }
11353
11354        //-- check if current user can use live lesson
11355        if ( 
11356            $isGuestViwer
11357            || empty($this->sharedUserData['User']) 
11358            || UserTable::canJoinLiveViewing($this->sharedUserData['User'])
11359        ){
11360            //-- set list of params for teacher live lessons
11361            $params = array(
11362                'user_id' => !empty($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : null,
11363                'payment_plan_id' => !empty($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null,
11364                'currency_code' => !empty($this->sharedUserData['User']['currency_code']) ? $this->sharedUserData['User']['currency_code'] : null,
11365                'user_language' => isset($this->localizeDir) ? $this->localizeDir : $this->sharedUserData['User']['native_language2'],
11366                'pc_view' => true,
11367                'page' => $currentPage,
11368                'template' => isset($data['template']) ? $data['template'] : '',
11369                'mobapp_view' => isset($data['template']) ? true : false,
11370                'limit' => $limit,
11371                'isGuestViwer' => $isGuestViwer,
11372                'isMobile' => !empty($data['isMobile']) ? 1 : 0, // TODO: Add new key-value pair if it is an SP view or mobileApp
11373            );
11374            // Get list of teachers for live lessons
11375            $liveTeacherList = $this->CommonTeacherStatus->liveTeacherList($params);
11376        }
11377        //-- return blank respond
11378        if ( empty($liveTeacherList) ) {
11379            $this->autoRender = false;
11380            $this->layout = false;
11381            return false;
11382        }
11383        // - pass view parameters
11384        $this->set('ajaxDisplay', true);
11385        $this->set('userJpTimeDiffSecond', $userJpTimeDiffSecond);
11386        $this->set('liveTeacherList', $liveTeacherList);
11387        $this->set('studentLessonPriorityTimeDelayInSeconds', (int)$this->studentLessonPriorityTimeDelayInSeconds);
11388        //-- if guest viwer with SP screen
11389        if ( $isGuestViwer && !empty($data['isMobile']) ) {
11390            $this->set('teacherListLiveParameters', $params); //TODO:: Pass the params to live_teacher_banner only in SP_side
11391            return $this->render('/Elements/mobile/live_teacher_banner_list');
11392        }
11393
11394        // - if usage template
11395        if (isset($data['template']) && in_array($data['template'], ["pc_usage", "mobapp_usage"])) {
11396            return $this->render('/Elements/live_teacher_pc_usage_list');
11397
11398        // - else use default
11399        } else {
11400            return $this->render('/Elements/live_teacher_banner_list');
11401        }
11402    }
11403
11404    /**
11405     * @api {get} /user/waiting/sms_questionnaire sms_questionnaire()
11406     * @apiName sms_questionnaire
11407     * @apiGroup Waiting
11408     * @apiDescription Redirects the user to the SMS questionnaire page for a specific teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11409     *
11410     * @apiBody {String} teacherId The ID of the teacher.
11411     * 
11412     * @apiSuccess {String} redirect The URL to redirect to.
11413     *
11414     * @apiSuccessExample {view} Redirect-Response:
11415     *  - Redirects to the /account/sms_questionnaire page.
11416     *
11417     * @apiError {String} error Message indicating the error.
11418     *
11419     * @apiErrorExample {json} Error-Response:
11420     *     {
11421     *         "error": "Invalid request."
11422     *     }
11423     * 
11424     * @apiSampleRequest off
11425     */
11426    public function sms_questionnaire($teacherId = null) {
11427        if (is_null($teacherId)) {
11428            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11429        }
11430        $data = array(
11431            'origin_url' => '/waiting/detail/'.$teacherId,
11432            'success_url' => '/waiting/detail/'.$teacherId
11433        );        
11434        $this->Session->write($data);
11435        return $this->redirect('/account/sms_questionnaire');
11436    }
11437    
11438    /**
11439     * @api {get} /user/waiting/avatar_sms_questionnaire avatar_sms_questionnaire()
11440     * @apiName avatar_sms_questionnaire
11441     * @apiGroup Waiting
11442     * @apiDescription Redirects the user to the SMS questionnaire page for a specific avatar teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11443     *
11444     * @apiBody {String} teacherId The ID of the avatar teacher.
11445     * 
11446     * @apiSuccess {String} redirect The URL to redirect to.
11447     *
11448     * @apiSuccessExample {view} Redirect-Response:
11449     *  - Redirects to the /account/sms_questionnaire page.
11450     *
11451     * @apiError {String} error Message indicating the error.
11452     *
11453     * @apiErrorExample {json} Error-Response:
11454     *     {
11455     *         "error": "Invalid request."
11456     *     }
11457     * 
11458     * @apiSampleRequest off
11459     */
11460    public function avatar_sms_questionnaire($teacherId = null) {
11461        if (is_null($teacherId)) {
11462            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11463        }
11464        $data = array(
11465            'origin_url' => '/avatar_detail/'.$teacherId,
11466            'success_url' => '/avatar_detail/'.$teacherId
11467        );        
11468        $this->Session->write($data);
11469        return $this->redirect('/account/sms_questionnaire');
11470    }
11471
11472    /**
11473     * @api {post} /user/waiting/checkCounselorTeacherButtonStatus checkCounselorTeacherButtonStatus()
11474     * @apiName checkCounselorTeacherButtonStatus
11475     * @apiGroup Waiting
11476     * @apiDescription Checks the status of the counselor teacher button for the authenticated user in Native Camp. It returns the availability of the counselor teacher, whether the daily limit is exceeded, and other related data.
11477     *
11478     * @apiBody {Boolean} [dev_test] Indicates whether the request is for development testing.
11479     * @apiBody {Boolean} [customer_support_flg] Indicates whether customer support is enabled.
11480     * 
11481     * @apiSuccess {String} available_teacher The ID of the available teacher.
11482     * @apiSuccess {Boolean} exceed_daily_limit Indicates whether the daily limit is exceeded.
11483     * @apiSuccess {Number} res The result status (0: Not available, 1: Available, 3: Logout).
11484     * @apiSuccess {String} chat_hash The chat hash.
11485     * @apiSuccess {Number} Membership type for checking if the user is not free trial
11486     *
11487     * @apiSuccessExample {json} Success-Response:
11488     *     {
11489     *         "available_teacher": "123",
11490     *         "exceed_daily_limit": 0,
11491     *         "res": 1,
11492     *         "chat_hash": "example_chat_hash",
11493     *            "membership_type": "example_membership_type"
11494     *     }
11495     *
11496     * @apiError {String} error Message indicating the error.
11497     *
11498     * @apiErrorExample {json} Error-Response:
11499     *     {
11500     *         "error": "Invalid request."
11501     *     }
11502     * 
11503     * @apiSampleRequest off
11504     */
11505    public function checkCounselorTeacherButtonStatus() {
11506        $this->autoRender = false;
11507        $this->layout = false;
11508        
11509        $result = 0; // Not available
11510        $devTest = isset($this->request->query['dev_test']) && $this->request->query['dev_test'] ? 1 : 0;
11511
11512        if (isset($this->request->data['customer_support_flg']) && ( $this->request->data['customer_support_flg'] == 'false' || $this->request->data['customer_support_flg'] == false )) {
11513            $customer_support_flg = 0;
11514        }else{
11515            $customer_support_flg = 1;
11516        }
11517        $userId = $this->Auth->user('id');
11518        $teacherId = 0;
11519        $exceedDailyLimit = false;
11520        $chat_hash = null;
11521        $userData = $this->sharedUserData['User'];
11522        if ( $this->request->is('ajax') || $devTest ) {
11523            if ( $userId ) {
11524                $counselorParams = array(
11525                    'user_id' => $userId,
11526                    'user_data' => $userData,
11527                    'customer_support_flg' => $customer_support_flg
11528                );
11529                $data = $this->LessonOnair->checkCounselorTeacherButtonStatus($counselorParams);
11530                $dataObj = json_decode($data,true);
11531                $teacherId = $dataObj['available_teacher'] ?? '';
11532                $exceedDailyLimit = $dataObj['exceed_daily_limit'] ?? '';
11533                $result = $dataObj['res'] ?? '';
11534                $chat_hash = $dataObj['chat_hash'] ?? '';
11535            } else {
11536                $result = 3; // logout
11537            }
11538        }
11539
11540        if($userId){
11541            $csList = ($customer_support_flg == 1) ? $this->Teacher->getCustomerSupportTeachers() : $this->Teacher->getCounselorTeachers();
11542            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, ($customer_support_flg == 1) ?  $csList['customerSupportId'] : $csList['counselorId']);
11543            if($csExceedLimitCheck){
11544                $exceedDailyLimit = true;
11545            }
11546        }
11547
11548        return json_encode(
11549            array(
11550                'available_teacher' => $teacherId,
11551                'exceed_daily_limit' => ( $exceedDailyLimit ) ? 1 : 0,
11552                'res' => $result,
11553                'chat_hash' => $chat_hash,
11554                'membership_type' => $this->userMembershipType
11555            )
11556        );
11557    }
11558
11559    /**
11560     * @api {get} /user/emergency emergencyLesson()
11561     * @apiName emergencyLesson
11562     * @apiGroup Waiting
11563     * @apiDescription Retrieves the emergency lesson data for the authenticated user in Native Camp. It checks if the user is a Study Sapuri TOS user and returns the preset textbook data.
11564     * 
11565     * @apiSuccess {Object} preset The preset textbook data.
11566     * @apiSuccess {String} preset.textbook_connect_id The ID of the textbook connect.
11567     * @apiSuccess {String} preset.textbook_type The type of the textbook.
11568     * @apiSuccess {Object} searchData The saved search condition data.
11569     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
11570     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
11571     *
11572     * @apiSuccessExample {json} Success-Response
11573     *     {
11574     *         "preset": {
11575     *             "textbook_connect_id": "123",
11576     *             "textbook_type": "1"
11577     *         },
11578     *         "searchData": {...},
11579     *         "textbookConnectId": "123",
11580     *         "textbookCategoryTypeId": "1"
11581     *     }
11582     *
11583     * @apiError {String} error Message indicating the error.
11584     *
11585     * @apiErrorExample {json} Error-Response:
11586     *     {
11587     *         "error": "Not Found"
11588     *     }
11589     * 
11590     * @apiSampleRequest off
11591     */
11592    public function emergencyLesson() {
11593        if (!$this->isStudySapuriTosUser) {
11594            throw new NotFoundException();
11595        }
11596
11597        $presetParams = array("user_id" => $this->Auth->user('id'));
11598        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
11599        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
11600                # for preset
11601                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
11602                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11603        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
11604                # use last viewed textbook if no preset data.
11605                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
11606                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11607        }
11608        
11609        # fetch preset 
11610        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11611        if(!$preset) {
11612                unset($presetParams['connect_id']);
11613                unset($presetParams['last_opened_date']);
11614                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11615        }
11616
11617        // NC-7228 set series id from saved search condition
11618        $searchData = $this->Cookie->read('searchData');
11619        $this->set('preset', $preset);
11620        $this->set('searchData', $searchData);
11621        $this->set('textbookConnectId', $preset['textbook_connect_id']);
11622        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
11623        return $this->render('/Waiting/emergency_lesson');
11624    }
11625    
11626    /**
11627     * @api {post} /user/waiting/teacherBadgeList teacherBadgeList()
11628     * @apiName teacherBadgeList
11629     * @apiGroup Waiting
11630     * @apiDescription Retrieves the badge list for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11631     *
11632     * @apiBody {String} teacherId The ID of the teacher.
11633     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11634     * 
11635     * @apiSuccess {Object[]} series The series data.
11636     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11637     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11638     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11639     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11640     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11641     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11642     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11643     * @apiSuccess {Object} teacherTbRatings The teacher textbook ratings data.
11644     * @apiSuccess {Number} teacherTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11645     * @apiSuccess {Object[]} titleThresholdTextbookList The title threshold textbook list data.
11646     * @apiSuccess {String} titleThresholdTextbookList.title The title of the threshold.
11647     * @apiSuccess {Number} titleThresholdTextbookList.threshold The threshold value.
11648     *
11649     * @apiSuccessExample {json} Success-Response:
11650     *     {
11651     *         "series": [
11652     *             {
11653     *                 "TextbookCategory": {
11654     *                     "name": "Category Name",
11655     *                     "id": "1",
11656     *                     "type_id": "2",
11657     *                     "image_big_url": "http://example.com/image.jpg"
11658     *                 },
11659     *                 "TeacherBadge": {
11660     *                     "textbook_category_id": "1",
11661     *                     "badge_flg": true
11662     *                 },
11663     *                 "gl_name": "Global Category Name"
11664     *             }
11665     *         ],
11666     *         "teacherTbRatings": {
11667     *             "1": {
11668     *                 "teacher_textbook_rating": 4.5
11669     *             }
11670     *         },
11671     *         "titleThresholdTextbookList": [
11672     *             {
11673     *                 "title": "Expert",
11674     *                 "threshold": 100
11675     *             },
11676     *             {
11677     *                 "title": "Master",
11678     *                 "threshold": 200
11679     *             }
11680     *         ]
11681     *     }
11682     *
11683     * @apiError {String} error Message indicating the error.
11684     *
11685     * @apiErrorExample {json} Error-Response:
11686     *     {
11687     *         "error": "Invalid request."
11688     *     }
11689     * 
11690     * @apiSampleRequest off
11691     */
11692    public function teacherBadgeList() {
11693        $this->layout = "";
11694        if (!$this->request->is('ajax')) { return ; }
11695        
11696        $teacherId = $this->request->data['teacherId'];
11697        if (empty($teacherId)) { return ; }
11698
11699        $fieldArr = array(
11700            'TextbookCategory.name',
11701            'TextbookCategory.id',
11702            'TextbookCategory.type_id',
11703            'TeacherBadge.textbook_category_id',
11704            'TeacherBadge.badge_flg',
11705            'TextbookCategory.type_id',
11706            'TextbookCategory.image_big_url'
11707        );
11708        $joinArr = array(
11709            array(
11710                'table' => 'teacher_badges',
11711                'alias' => 'TeacherBadge',
11712                'type' => 'INNER',
11713                'conditions' => array(
11714                    'TeacherBadge.textbook_category_id = TextbookCategory.id',
11715                    'TeacherBadge.teacher_id' => $teacherId)
11716            )
11717        );
11718
11719        // if the user's language is zh-tw, display chinese textbook badge name
11720        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11721            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11722            if($langId){
11723                $joinArr[] = array(
11724                    'type' => 'LEFT',
11725                    'table' => 'global_textbook_categories',
11726                    'alias' => 'GlobalTextbookCategory',
11727                    'conditions' => array(
11728                        'GlobalTextbookCategory.language_id' => $langId,
11729                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11730                    )
11731                );
11732                $this->TextbookCategory->virtualFields = array(
11733                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11734                );
11735                $fieldArr[] = 'gl_name';
11736            }
11737        }
11738
11739        $conArr = array(
11740            'TextbookCategory.status' => 1,
11741            'TextbookCategory.type_id' => 2
11742        );
11743
11744        # get studydapuri textbooks
11745        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11746        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11747            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11748            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11749        } elseif ($this->isStudySapuriTosUser) {
11750            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11751        } else {
11752            $exCat = Configure::read('all_sapuri_textbook_category_types');
11753            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11754        }
11755
11756        // NJ-5836
11757        $displayRestrictionParams = array(
11758            'lang' => $this->localizeDir
11759        );
11760
11761        // get display restriction setting
11762        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11763
11764        // NJ-5836 add condition for display restriction
11765        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11766            // set condition for display restriction
11767            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11768        }
11769
11770        //get series and badge
11771        $series = $this->TextbookCategory->find('all', array(
11772            'fields' => $fieldArr,
11773            'conditions' => $conArr,
11774            'joins' => $joinArr,
11775            'order' => array(
11776                'TextbookCategory.sort' => 'ASC'
11777            )
11778        ));
11779
11780        $this->set('series', $series);            
11781        
11782        $teacherTbRatings = array();
11783        if($series && is_array($series)) {
11784            foreach($series as $key => $books){            
11785                $categoryId = $books['TextbookCategory']['id'];
11786                $params = array(
11787                    'teacher_id' =>  (int) $teacherId,
11788                    'textbook_category_id' => (int) $categoryId,
11789                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11790                );    
11791                $decodeResp = json_decode($this->TeacherTextbookStat->teacherTextbookRating($params));
11792                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11793            }
11794        }
11795        $this->set('teacherTbRatings', $teacherTbRatings);
11796
11797        // NJ-17264
11798        $titleThresholdTextbookList = $this->TitleThresholdTeacher->getTitleTresholdPerTextbookCategory(['teacherId' => $teacherId, 'type' => 0]);    
11799
11800        $this->set('titleThresholdTextbookList', $titleThresholdTextbookList);
11801
11802        // new UI
11803        $this->render('teacher_badge_list');
11804        if( isset($this->request->data['sp']) && $this->request->data['sp'] ) {
11805            $this->render('sp_teacher_badge_list');
11806        }
11807    }
11808
11809    /**
11810     * @api {post} /user/waiting/avatarBadgeList avatarBadgeList()
11811     * @apiName avatarBadgeList
11812     * @apiGroup Waiting
11813     * @apiDescription Retrieves the badge list for a specific avatar teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11814     *
11815     * @apiBody {String} teacher_avatar_id The ID of the avatar teacher.
11816     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11817     * 
11818     * @apiSuccess {Object[]} series The series data.
11819     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11820     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11821     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11822     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11823     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11824     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11825     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11826     * @apiSuccess {Object} avatarTbRatings The avatar textbook ratings data.
11827     * @apiSuccess {Number} avatarTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11828     *
11829     * @apiSuccessExample {json} Success-Response:
11830     *     {
11831     *         "series": [
11832     *             {
11833     *                 "TextbookCategory": {
11834     *                     "name": "Category Name",
11835     *                     "id": "1",
11836     *                     "type_id": "2",
11837     *                     "image_big_url": "http://example.com/image.jpg"
11838     *                 },
11839     *                 "TeacherBadge": {
11840     *                     "textbook_category_id": "1",
11841     *                     "badge_flg": true
11842     *                 },
11843     *                 "gl_name": "Global Category Name"
11844     *             }
11845     *         ],
11846     *         "avatarTbRatings": {
11847     *             "1": {
11848     *                 "teacher_textbook_rating": 4.5
11849     *             }
11850     *         }
11851     *     }
11852     *
11853     * @apiError {String} error Message indicating the error.
11854     *
11855     * @apiErrorExample {json} Error-Response:
11856     *     {
11857     *         "error": "Invalid request."
11858     *     }
11859     * 
11860     * @apiSampleRequest off
11861     */
11862    public function avatarBadgeList() {
11863        $this->layout = "";
11864
11865        if (!$this->request->is('ajax')) { return; }
11866        
11867        $avatarId = Sanitize::escape($this->request->data['teacher_avatar_id']);
11868
11869        if (empty($avatarId)) { return; }
11870
11871        $fieldArr = array(
11872            'TextbookCategory.name',
11873            'TextbookCategory.id',
11874            'TextbookCategory.type_id',
11875            'TeacherBadge.textbook_category_id',
11876            'TeacherBadge.badge_flg',
11877            'TextbookCategory.type_id',
11878            'TextbookCategory.image_big_url'
11879        );
11880        $joinArr = array(
11881            array(
11882                'table' => 'teacher_badges',
11883                'alias' => 'TeacherBadge',
11884                'type' => 'INNER',
11885                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $avatarId)
11886            )
11887        );
11888
11889        // if the user's language is zh-tw, display chinese textbook badge name
11890        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11891            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11892            if($langId){
11893                $joinArr[] = array(
11894                    'type' => 'LEFT',
11895                    'table' => 'global_textbook_categories',
11896                    'alias' => 'GlobalTextbookCategory',
11897                    'conditions' => array(
11898                        'GlobalTextbookCategory.language_id' => $langId,
11899                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11900                    )
11901                );
11902                $this->TextbookCategory->virtualFields = array(
11903                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11904                );
11905                $fieldArr[] = 'gl_name';
11906            }
11907        }
11908
11909        $conArr = array(
11910            'TextbookCategory.status' => 1,
11911            'TextbookCategory.type_id' => 2
11912        );
11913
11914        # get studydapuri textbooks
11915        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11916        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11917            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11918            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11919        } elseif ($this->isStudySapuriTosUser) {
11920            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11921        } else {
11922            $exCat = Configure::read('all_sapuri_textbook_category_types');
11923            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11924        }
11925
11926        // NJ-5836
11927        $displayRestrictionParams = array(
11928            'lang' => $this->localizeDir
11929        );
11930
11931        // get display restriction setting
11932        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11933
11934        // NJ-5836 add condition for display restriction
11935        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11936            // set condition for display restriction
11937            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11938        }
11939
11940        //get series and badge
11941        $series = $this->TextbookCategory->find('all', array(
11942            'fields' => $fieldArr,
11943            'conditions' => $conArr,
11944            'joins' => $joinArr,
11945            'order' => array(
11946                'TextbookCategory.sort' => 'ASC'
11947            )
11948        ));
11949
11950        $this->set('series', $series);
11951
11952        $avatarTbRatings = array();
11953        if($series && is_array($series)) {
11954            foreach($series as $key => $books){            
11955                $categoryId = $books['TextbookCategory']['id'];
11956                $params = array(
11957                    'avatar_id' => $avatarId,
11958                    'textbook_category_id' => (int) $categoryId,
11959                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11960                );    
11961                $decodeResp = json_decode($this->TeacherTextbookStat->avatarTextbookRating($params));
11962                $avatarTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11963            }
11964        }
11965        $this->set('avatarTbRatings', $avatarTbRatings);
11966        
11967        if(isset($this->request->data['sp']) && $this->request->data['sp']) {
11968            $this->set('avatar_sp', 1);
11969            $this->render('sp_teacher_badge_list');
11970        }
11971
11972    }    
11973
11974    /**
11975     * @api {post} /user/waiting/teacherOccupation teacherOccupation()
11976     * @apiName teacherOccupation
11977     * @apiGroup Waiting
11978     * @apiDescription Retrieves the occupation history of a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the teacher occupation data.
11979     *
11980     * @apiBody {String} teacherId The ID of the teacher.
11981     * 
11982     * @apiSuccess {Object[]} teacherOccupation The teacher occupation data.
11983     * @apiSuccess {String} teacherOccupation.id The ID of the occupation detail.
11984     * @apiSuccess {String} teacherOccupation.teacher_id The ID of the teacher.
11985     * @apiSuccess {String} teacherOccupation.occupation The occupation of the teacher.
11986     * @apiSuccess {String} teacherOccupation.start_date The start date of the occupation.
11987     * @apiSuccess {String} teacherOccupation.end_date The end date of the occupation.
11988     * @apiSuccess {String} lang The language code for the page.
11989     *
11990     * @apiSuccessExample {json} Success-Response:
11991     *     {
11992     *         "teacherOccupation": [
11993     *             {
11994     *                 "id": "1",
11995     *                 "teacher_id": "123",
11996     *                 "occupation": "Software Engineer",
11997     *                 "start_date": "2020-01-01",
11998     *                 "end_date": "2021-01-01"
11999     *             },
12000     *             {
12001     *                 "id": "2",
12002     *                 "teacher_id": "123",
12003     *                 "occupation": "Project Manager",
12004     *                 "start_date": "2021-02-01",
12005     *                 "end_date": "2022-01-01"
12006     *             }
12007     *         ],
12008     *         "lang": "en"
12009     *     }
12010     *
12011     * @apiError {String} error Message indicating the error.
12012     *
12013     * @apiErrorExample {json} Error-Response:
12014     *     {
12015     *         "error": "Invalid request."
12016     *     }
12017     * 
12018     * @apiSampleRequest off
12019     */
12020    public function teacherOccupation() {
12021        $this->layout = "";
12022        if (!$this->request->is('ajax')) { return ; }
12023        
12024        $teacherId = $this->request->data['teacherId'];
12025        if (empty($teacherId)) { return ; }
12026
12027        //NC-9215 get teacher occupation history
12028        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
12029        $this->set('teacherOccupation', $teacherOccupation);
12030        $lang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language');
12031        $this->set('lang', $lang);        
12032
12033        $this->render('teacher_occupation');
12034    }
12035
12036     //only used in this class controller
12037     //Retrieves the features of a specific teacher in Native Camp. It checks if the request is an AJAX request or if it is called from SP, and returns the teacher features data.
12038    public function teacherFeatures($sp = false, $teacherId = null) {
12039        $this->autoRender = false;
12040        $this->layout = false;
12041        if ($this->request->is('ajax') || $sp) {
12042            $teacherId = $this->request->data['teacherId'] ?? $teacherId;
12043            if (empty($teacherId)) { return ; }
12044    
12045            $feature = $this->TeacherFeature->find('first', array(
12046                'conditions' =>  array(
12047                    'TeacherFeature.teacher_id' => $teacherId
12048                )
12049            ));
12050            return json_encode(isset($feature['TeacherFeature']) ? $feature['TeacherFeature'] : array());
12051        } return;
12052    }
12053
12054    /**
12055     * @api {post} /user/waiting/getSelfReviews getSelfReviews()
12056     * @apiName getSelfReviews
12057     * @apiGroup Waiting
12058     * @apiDescription Retrieves the self-reviews for a specific teacher and user in Native Camp. It checks if the request is an AJAX request and returns the self-reviews data.
12059     *
12060     * @apiBody {String} teacherId The ID of the teacher.
12061     * @apiBody {String} userId The ID of the user.
12062     * 
12063     * @apiSuccess {Object[]} selfReviews The self-reviews data.
12064     * @apiSuccess {String} selfReviews.review The review text.
12065     * @apiSuccess {Number} selfReviews.rating The rating given by the user.
12066     * @apiSuccess {String} selfReviews.date The date of the review.
12067     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
12068     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
12069     * @apiSuccess {String} lessonHistoryTeacherId The ID of the teacher for the lesson history.
12070     *
12071     * @apiSuccessExample {json} Success-Response:
12072     *     {
12073     *         "selfReviews": [
12074     *             {
12075     *                 "review": "Great lesson!",
12076     *                 "rating": 5,
12077     *                 "date": "2023-01-01"
12078     *             },
12079     *             {
12080     *                 "review": "Very helpful.",
12081     *                 "rating": 4,
12082     *                 "date": "2023-01-02"
12083     *             }
12084     *         ],
12085     *         "selfLessonCount": 5,
12086     *         "daysPast": 10,
12087     *         "lessonHistoryTeacherId": "123"
12088     *     }
12089     *
12090     * @apiError {String} error Message indicating the error.
12091     *
12092     * @apiErrorExample {json} Error-Response:
12093     *     {
12094     *         "error": "Invalid request."
12095     *     }
12096     * 
12097     * @apiSampleRequest off
12098     */
12099    public function getSelfReviews() {
12100        $this->layout = "";
12101        $this->autoRender = false;
12102        if (!$this->request->is('ajax')) { return ; }
12103        
12104        $teacherId = $this->request->data['teacherId'];
12105        if (empty($teacherId)) { return ; }
12106
12107        $userId = $this->request->data['userId'];
12108
12109        //get own reviews
12110        $selfReviews = array();
12111        $selfLessonCount = 0;
12112        $daysPast = 0;
12113        if ($userId) {
12114            $selfReviews = $this->getUserReviews($userId, $teacherId);
12115            $selfLessonCount = $this->LessonOnairsLog->countOwnLessons($userId, $teacherId);
12116            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
12117        }
12118
12119        $this->set('selfReviews', $selfReviews);
12120        $this->set('selfLessonCount', $selfLessonCount);
12121        $this->set('daysPast', $daysPast);
12122        $this->set('lessonHistoryTeacherId',$teacherId);
12123
12124        $this->render('/Elements/self_review');
12125    }
12126
12127    /**
12128     * @api {post} /user/waiting/getGenerationRating getGenerationRating()
12129     * @apiName getGenerationRating
12130     * @apiGroup Waiting
12131     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the rating data.
12132     *
12133     * @apiBody {String} teacherId The ID of the teacher.
12134     * @apiBody {Boolean} [isAvatar] Indicates whether the teacher is an avatar.
12135     * 
12136     * @apiSuccess {Object} rates The generation rating data.
12137     * @apiSuccess {Number} rates.count The total number of ratings.
12138     * @apiSuccess {Number} rates.one_star The number of one-star ratings.
12139     * @apiSuccess {Number} rates.two_star The number of two-star ratings.
12140     * @apiSuccess {Number} rates.three_star The number of three-star ratings.
12141     * @apiSuccess {Number} rates.four_star The number of four-star ratings.
12142     * @apiSuccess {Number} rates.five_star The number of five-star ratings.
12143     * @apiSuccess {Object} rateBreakdown The breakdown of the generation rating data.
12144     * @apiSuccess {Number} rateBreakdown.weekly_average The weekly average rating.
12145     * @apiSuccess {Number} rateBreakdown.monthly_average The monthly average rating.
12146     * @apiSuccess {Number} rateBreakdown.total_average The total average rating.
12147     *
12148     * @apiSuccessExample {json} Success-Response:
12149     *     {
12150     *         "rates": {
12151     *             "count": 100,
12152     *             "one_star": 10,
12153     *             "two_star": 20,
12154     *             "three_star": 30,
12155     *             "four_star": 25,
12156     *             "five_star": 15
12157     *         },
12158     *         "rateBreakdown": {
12159     *             "weekly_average": 4.2,
12160     *             "monthly_average": 4.0,
12161     *             "total_average": 4.1
12162     *         }
12163     *     }
12164     *
12165     * @apiError {String} error Message indicating the error.
12166     *
12167     * @apiErrorExample {json} Error-Response:
12168     *     {
12169     *         "error": "Invalid request."
12170     *     }
12171     * 
12172     * @apiSampleRequest off
12173     */
12174    public function getGenerationRating() {
12175        $this->layout = "";
12176        $this->autoRender = false;
12177        
12178        if (!$this->request->is('ajax')) { return ; }
12179        
12180        $teacherId = Sanitize::escape($this->request->data['teacherId']);
12181        if (empty($teacherId)) { return ; }
12182
12183        $isAvatar = (isset($this->request->data['isAvatar']) && $this->request->data['isAvatar']) ? true : false;
12184        if($isAvatar){
12185            $teacherId = $this->Teacher->getAvatarTeacherId(array('avatar_id' => $teacherId));
12186            $rating = $this->UsersClassEvaluation->getRatings($avatarIds, true);
12187        }
12188
12189        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12190        if ($rating) {
12191            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12192            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12193        }
12194        $this->set('rates', $rates);        
12195        $this->set('rateBreakdown', $rateBreakdown);        
12196
12197        $this->render('teacher_generation_rating');
12198    }
12199
12200    /**
12201     * @api {post} /user/api/getGenerationRating getGenerationRatingAPI()
12202     * @apiName getGenerationRatingAPI
12203     * @apiGroup Waiting
12204     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks the teacher ID and user token, and returns the rating data.
12205     *
12206     * @apiBody {String} teacher_id The ID of the teacher.
12207     * @apiBody {String} users_api_token The API token of the user.
12208     * 
12209     * @apiSuccess {Object} generationData The generation rating data. (0: 20, 1: 30, 2: 50)
12210     *
12211     * @apiSuccessExample {json} Success-Response:
12212     *     {
12213     *         "generationData": {
12214     *             "0": 20,
12215     *             "1": 30,
12216     *             "2": 50
12217     *         }
12218     *     }
12219     *
12220     * @apiError {Object} error The error details.
12221     * @apiError {String} error.id The error ID.
12222     * @apiError {String} error.message The error message.
12223     *
12224     * @apiErrorExample {json} Error-Response (Bad Request):
12225     *     {
12226     *         "error": {
12227     *             "id": "invalid_teacher_id",
12228     *             "message": "teacher_id is invalid"
12229     *         }
12230     *     }
12231      * @apiErrorExample {json} Error-Response (Unauthorized):
12232     *     {
12233     *         "error": {
12234     *             "id": "invalid_token",
12235     *             "message": "users_api_token is invalid"
12236     *         }
12237     *     }
12238     * 
12239     * @apiSampleRequest off
12240     */
12241    public function getGenerationRatingAPI(){
12242        $this->autoRender = false;
12243        $this->layout = false;
12244        $data = json_decode($this->request->input(), true);
12245        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12246        if (empty($teacherId)) { 
12247            $response['error']['id'] = _('invalid_teacher_id');
12248            $response['error']['message'] = __('teacher_id is invalid');
12249            return json_encode($response);
12250        }
12251        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12252        $userData = $this->User->getUserDataByApiToken($userToken);
12253        if(!$userData) {
12254            $response['error']['id'] = _('invalid_token');
12255            $response['error']['message'] = __('users_api_token is invalid');
12256            return json_encode($response);
12257        }
12258        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12259        if ($rating) {
12260            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12261            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12262        }
12263        $ctr = 0;
12264        foreach($rates as $rate){
12265            $generationData[$ctr] = ($rate / $rates->count) * 100; // get percentages for data
12266            $ctr++;
12267        }
12268        //remove count element at the end
12269        array_pop($generationData);
12270        return json_encode($generationData);
12271    }
12272
12273    public function getUserMemo(){
12274        $this->autoRender = false;
12275        $this->layout = false;
12276        $data = json_decode($this->request->input(), true);
12277        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12278        if (empty($teacherId)) { 
12279            $response['error']['id'] = _('invalid_teacher_id');
12280            $response['error']['message'] = __('teacher_id is invalid');
12281            return json_encode($response);
12282        }
12283        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12284        $userData = $this->User->getUserDataByApiToken($userToken);
12285        if(!$userData) {
12286            $response['error']['id'] = _('invalid_token');
12287            $response['error']['message'] = __('users_api_token is invalid');
12288            return json_encode($response);
12289        }
12290
12291        $getKeepMemo = $this->UsersMemo->find('first', array(
12292            'fields' => array(
12293                'id',
12294                'memo'
12295            ),
12296            'conditions' => array(
12297                'user_id' => $userData['id'],
12298                'teacher_id' => $teacherId,
12299                'type' => 0
12300            ),
12301            'order' => array('created DESC'),
12302        ));
12303        $memoData['id'] = $getKeepMemo['UsersMemo']['id'];
12304        $memoData['memo'] = $getKeepMemo['UsersMemo']['memo'];
12305        
12306        return json_encode($memoData);
12307    }
12308
12309    /**
12310     * @api {post} /user/waiting/getReservationCancellationBreakdown getReservationCancellationBreakdown()
12311     * @apiName getReservationCancellationBreakdown
12312     * @apiGroup Waiting
12313     * @apiDescription Retrieves the reservation and cancellation breakdown for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation and cancellation data.
12314     *
12315     * @apiBody {String} teacherId The ID of the teacher.
12316     * 
12317     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown data.
12318     * @apiSuccess {Number} reserveAndCancel.this_month_reserved The number of reservations made this month.
12319     * @apiSuccess {Number} reserveAndCancel.last_month_reserved The number of reservations made last month.
12320     * @apiSuccess {Number} reserveAndCancel.this_month_cancelled The number of reservations cancelled this month.
12321     * @apiSuccess {Number} reserveAndCancel.last_month_cancelled The number of reservations cancelled last month.
12322     * @apiSuccess {Number} reserveAndCancel.this_month_cancellation_rate The cancellation rate this month.
12323     * @apiSuccess {Number} reserveAndCancel.last_month_cancellation_rate The cancellation rate last month.
12324     * 
12325     * @apiSuccessExample {json} Success-Response:
12326     *     {
12327     *         "reserveAndCancel": {
12328     *             "this_month_reserved": 10,
12329     *             "last_month_reserved": 20,
12330     *             "this_month_cancelled": 5,
12331     *             "last_month_cancelled": 10,
12332     *             "this_month_cancellation_rate": 0.5
12333     *         }
12334     *     }
12335     *
12336     * @apiError {String} error Message indicating the error.
12337     *
12338     * @apiErrorExample {json} Error-Response:
12339     *     {
12340     *         "error": "Invalid request."
12341     *     }
12342     * 
12343     * @apiSampleRequest off
12344     */
12345    public function getReservationCancellationBreakdown() {
12346        $this->autoRender = false;
12347        $this->layout = false;
12348        if (!$this->request->is('ajax')) { return ; }
12349        
12350        $teacherId = $this->request->data['teacherId'];
12351        if (empty($teacherId)) { return ; }
12352
12353        //reservation and cancellation breakdown
12354        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
12355        return json_encode(isset($reserveAndCancel) ? $reserveAndCancel : array());
12356    }
12357
12358    // NJ-22649 transfer functionality from lesson-finish
12359    //not used function
12360    public function getActiveCampaign($params = array()) {
12361        $counseling_flg = (isset($params['counseling_flg']) && $params['counseling_flg']) ? true : false;
12362        $avatar_flg = (isset($params['avatar_flg']) && $params['avatar_flg']) ? true : false;
12363        $chat_hash = (isset($params['chat_hash']) && $params['chat_hash']) ? $params['chat_hash'] : '';
12364        $memberType = (isset($params['memberType']) && $params['memberType']) ? $params['memberType'] : 'student';
12365
12366        $campaignTerm = false;
12367        $modalCampaignType = '';
12368        $campaignPageRecord = '';
12369        $userId = $this->Auth->user('id');
12370        $userData = new UserTable($this->sharedUserData['User']);
12371
12372        $campaignSetting = ClassRegistry::init('CampaignSettingTable');
12373        $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12374        $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12375
12376        //Spring Callan Campaign
12377        $campaignSpringCallanPeriodFrom = Configure::read('campaign_config.callanFirstTime.period.start');
12378        $campaignSpringCallanPeriodTo = Configure::read('campaign_config.callanFirstTime.period.reservation_end');
12379        $campaignSpringCallan = $this->showCampaignModal($campaignSpringCallanPeriodFrom, $campaignSpringCallanPeriodTo);
12380
12381        //Campaign to talk with teachers from all over the world
12382        $campaignGlobalLesson = ClassRegistry::init('CampaignSettingTable')->globalLesson(array('user_id' => $userId, 'type' => 1)); //Check campaign duration date and if not sapuri user
12383        $sixthAnniv3Campaign = ClassRegistry::init('CampaignSettingTable')->sixthAnniv3(array('user_id' => $userId));
12384
12385        //Go to travel campaign
12386        $goToTravelDateArr = Configure::read('campaign_config.gototravel.period');
12387        $goToTravelCampaign = $this->showCampaignModal($goToTravelDateArr['start'], $goToTravelDateArr['end']);
12388
12389        //Alvark Collaboration Campaign
12390        $alvarkCollabCampaign = false;
12391        $alvarkCollabDateArr = Configure::read('campaign_config.alvark_collaboration.period');
12392        $alvarkCollabCheckDate = $this->showCampaignModal($alvarkCollabDateArr['start'], $alvarkCollabDateArr['end']);
12393        if (
12394            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collaboration.valid_memberships')) 
12395            && $userData->currency_code == Configure::read('default.user_currency')
12396            && $alvarkCollabCheckDate
12397            && $this->localizeDir == Configure::read('default.user_language')
12398        ) {
12399            $alvarkCollabCampaign = true;
12400        }
12401
12402        // Campaign Settings Modal
12403        $currStr = $userData->currency_code;
12404        $langId = ClassRegistry::init("CountryCode")->getUserLanguageId($userData->native_language2);
12405        $today = date('Y-m-d H:i:s');
12406        $conditions = array(
12407            'user_plan_type' => $userData->getMembershipTypeIndex(),
12408            'plan_types' => Configure::read('campaign_settings.plan_types'),
12409            'is_sapuri_user' => $userData->isStudySapuri(),
12410            'corporate_user_types' => Configure::read('campaign_settings.corporates'),
12411            'free_user_type' => Configure::read('campaign_settings.free_user_type'),
12412        );
12413
12414        $campaignUserPlanType = $userData->getUserPlanType($conditions);
12415        $this->log("[CampaignSettingsModal][after_lesson] conditions -> " .  json_encode($conditions), "debug");
12416        $campaignSettings = null;
12417        if ((isset($campaignUserPlanType['plan_type']) && $campaignUserPlanType['plan_type']) &&
12418            (isset($campaignUserPlanType['user_type']) && $campaignUserPlanType['user_type'])
12419        ) {
12420            $campaignSettingsModel = ClassRegistry::init('CampaignSettings');
12421            $campaignSettings = $campaignSettingsModel->getActiveAndNotEnded(array(
12422                'fields' => array(
12423                    'CampaignSettings.id',
12424                    'CampaignSettings.modal_html',
12425                    'CampaignSettings.pc_url',
12426                    'CampaignSettings.image_url_pc'
12427                ),
12428                'conditions' => array(
12429                    'CampaignSettings.promo_end >=' => $today,
12430                    'CampaignSettings.status_flag' => 1,
12431                    'CampaignSettings.promo_event_type' => 1, // after lesson
12432                    'CampaignSettings.pc_url IS NOT NULL',
12433
12434                    // os
12435                    array(
12436                        'OR' => array(
12437                            array('CampaignSettings.promo_os LIKE' => '%1%'), // pc
12438                            array('CampaignSettings.promo_os LIKE' => '%0%'), // all
12439                        )
12440                    ),
12441
12442                    // login status
12443                    array(
12444                        'OR' => array(
12445                            array('CampaignSettings.promo_login_status LIKE' => '%1%'), // sign in
12446                            array('CampaignSettings.promo_login_status LIKE' => '%0%'), // all
12447                        )
12448                    ),
12449
12450                    // Plan type
12451                    array(
12452                        'OR' => array(
12453                            array('CampaignSettings.promo_plan_type LIKE' => '%'.$campaignUserPlanType['plan_type'].'%'),
12454                            array('CampaignSettings.promo_plan_type LIKE' => '%0%'), // ALL
12455                        )
12456                    ),
12457
12458                    // User type
12459                    array(
12460                        'OR' => array(
12461                            array('CampaignSettings.promo_user_type LIKE' => '%'.$campaignUserPlanType['user_type'].'%'),
12462                            array('CampaignSettings.promo_user_type LIKE' => '%0%') // ALL
12463                        )
12464                    ),
12465
12466                    // Currency and Language
12467                    array(
12468                        "(SELECT COUNT(*) FROM `campaign_setting_currency` WHERE `CampaignSettings`.`id` = `campaign_setting_currency`.`campaign_setting_id` AND `campaign_setting_currency`.`currency_code` = '".$currStr."') > 0"
12469                    ),
12470                    array(
12471                        "(SELECT COUNT(*) FROM `campaign_setting_language` WHERE `CampaignSettings`.`id` = `campaign_setting_language`.`campaign_setting_id` AND `campaign_setting_language`.`language_id` = '".$langId."') > 0"
12472                    )
12473                ),
12474                'order' => 'CampaignSettings.promo_start ASC'
12475            ));
12476        }
12477
12478        //Marines Collaboration Campaign
12479        $marinesCollabCampaign = false;
12480        $marinesCollabDateArr = Configure::read('campaign_config.going_global_marines_collaboration.period');
12481        $marinesCollabCheckDate = $this->showCampaignModal($marinesCollabDateArr['start'], $marinesCollabDateArr['end']);
12482        if (
12483            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.going_global_marines_collaboration.valid_memberships')) 
12484            && $marinesCollabCheckDate
12485            && $this->localizeDir == Configure::read('default.user_language')
12486        ) {
12487            $marinesCollabCampaign = true;
12488        }
12489
12490        // //Daily News Campaign
12491        // $dailyNewsCampaign = false;
12492        // $dailyNewsDateArr = Configure::read('campaign_config.daily_news.period');
12493        // $dailyNewsCheckDate = $this->showCampaignModal($dailyNewsDateArr['start'], $dailyNewsDateArr['end']);
12494        // if (
12495        //     in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.daily_news.valid_memberships')) 
12496        //     && $dailyNewsCheckDate
12497        // ) {
12498        //     $dailyNewsCampaign = true;
12499        // }
12500
12501        //Favorite Teacher Campaign
12502        $favoriteTeacherCampaign = false;
12503        $favoriteTeacherDateArr = Configure::read('campaign_config.favorite_teacher.period');
12504        $favoriteTeacherCheckDate = $this->showCampaignModal($favoriteTeacherDateArr['start'], $favoriteTeacherDateArr['end']);
12505        if (
12506            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.favorite_teacher.valid_memberships')) 
12507            && $favoriteTeacherCheckDate
12508        ) {
12509            $favoriteTeacherCampaign = true;
12510        }
12511
12512        //Family Plan Campaign
12513        $familyPlanCampaign = false;
12514        $familyPlanDateArr = Configure::read('campaign_config.family_plan.period');
12515        $familyPlanCheckDate = $this->showCampaignModal($familyPlanDateArr['start'], $familyPlanDateArr['end']);
12516        if (
12517            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.family_plan.valid_memberships')) 
12518            && $familyPlanCheckDate
12519        ) {
12520            $familyPlanCampaign = true;
12521        }
12522
12523        //Christmas Campaign
12524        $christmasCampaign = false;
12525        $christmasDateArr = Configure::read('campaign_config.christmas.period');
12526        $christmasCheckDate = $this->showCampaignModal($christmasDateArr['start'], $christmasDateArr['end']);
12527        if (
12528            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.christmas.valid_memberships')) 
12529            && $christmasCheckDate
12530        ) {
12531            $christmasCampaign = true;
12532        }
12533
12534        //New year Part 1 Campaign
12535        $newYearPart1Campaign = false;
12536        $newYearPart1DateArr = Configure::read('campaign_config.new_year_part_1.period');
12537        $newYearPart1CheckDate = $this->showCampaignModal($newYearPart1DateArr['start'], $newYearPart1DateArr['end']);
12538        if (
12539            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_year_part_1.valid_memberships')) 
12540            && ($userData->admin_flg || $newYearPart1CheckDate) 
12541            && $this->localizeDir == Configure::read('default.user_language')
12542        ) {
12543            $newYearPart1Campaign = true;
12544        }
12545
12546        //New grammar Campaign
12547        $newGrammarCampaign = false;
12548        $newGrammarDateArr = Configure::read('campaign_config.new_grammar.period');
12549        $newGrammarCheckDate = $this->showCampaignModal($newGrammarDateArr['start'], $newGrammarDateArr['end']);
12550        if (
12551            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_grammar.valid_memberships')) 
12552            && $newGrammarCheckDate
12553        ) {
12554            $newGrammarCampaign = true;
12555        }
12556
12557        //Alvark collab Campaign
12558        $alvarkCollab2Campaign = false;
12559        $alvarkCollab2DateArr = Configure::read('campaign_config.alvark_collab_2.period');
12560        $alvarkCollab2CheckDate = $this->showCampaignModal($alvarkCollab2DateArr['start'], $alvarkCollab2DateArr['end']);
12561        if (
12562            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collab_2.valid_memberships')) 
12563            && $alvarkCollab2CheckDate
12564            && $this->localizeDir == Configure::read('default.user_language')
12565        ) {
12566            $alvarkCollab2Campaign = true;
12567        }
12568
12569        //Golden Week NC Campaign
12570        $goldenWeekNCChallengeCampaign = false;
12571        $goldenWeekNCChallengeDateArr = Configure::read('campaign_config.golden_week_nc_challenge.period');
12572        $goldenWeekNCChallengeCheckDate = $this->showCampaignModal($goldenWeekNCChallengeDateArr['start'], $goldenWeekNCChallengeDateArr['end']);
12573        if (
12574            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.golden_week_nc_challenge.valid_memberships')) 
12575            && $goldenWeekNCChallengeCheckDate
12576        ) {
12577            $goldenWeekNCChallengeCampaign = true;
12578        }
12579
12580        if ($campaignSpringCallan) {
12581            $campaignTerm = $campaignSpringCallan;
12582            $modalCampaignType = 'campaign_callan_half_spring';
12583            $campaignPageRecord = 'callan_half_spring_record';
12584            // check if not a sapuri student
12585            $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12586            if (in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.callanFirstTime.membership'))) {        
12587                /* count callan lesson taken within the campaign period */
12588                $countCallanLesson = ClassRegistry::init('CampaignSettingTable')->callanMarathonCampaign(array(
12589                    'user_id' => $this->Auth->user("id"),
12590                    'date_period' => array(
12591                            Configure::read('campaign_config.callanFirstTime.period.start'),
12592                            Configure::read('campaign_config.callanFirstTime.period.reservation_end')
12593                        ),
12594                    'tb_category_id' => Configure::read('campaign_config.callanFirstTime.textbook_category')
12595                ));
12596                $response['countCallanLesson'] = $countCallanLesson;
12597            }
12598
12599        } else if ($campaignGlobalLesson) {
12600            //If not counseling: display modal stamp
12601            if (!$counseling_flg) {
12602                $campaignTerm = $campaignGlobalLesson;
12603                $modalCampaignType = 'campaign_global_lesson';
12604                $campaignPageRecord = 'global_lesson_record';
12605            }
12606        } else if ($sixthAnniv3Campaign) {
12607            $campaignTerm = $sixthAnniv3Campaign;
12608            $modalCampaignType = 'campaign_sixth_anniv_3';
12609            $campaignPageRecord = 'sixth_anniv_record';
12610
12611        //Go to travel campaign
12612        } else if ($goToTravelCampaign) {
12613            if (!$counseling_flg) {
12614                $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12615                $stampAchieved = array();
12616                if (!in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.gototravel.membership_invalid'))) {
12617                    // get student achieved lesson stamps
12618                    $stampAchieved = ClassRegistry::init('CampaignSettingTable')->camapaignGoToTravelTbStamp(array(
12619                        'user_id' => $this->Auth->user( 'id' ),
12620                        'start_time' => Configure::read('campaign_config.gototravel.period.start'),
12621                        'end_time' => Configure::read('campaign_config.gototravel.period.end'),
12622                        'tb_connect_ids' => array_values(array_flip(Configure::read('campaign_config.gototravel.textbook_connect'))),
12623                        'lesson_min_time' => Configure::read('campaign_config.gototravel.lesson_time')
12624                    ));
12625                    $stampAchieved = is_array($stampAchieved) ? array_values($stampAchieved) : $stampAchieved;
12626                    $response['stampAchieved'] = $stampAchieved;
12627                    $modalCampaignType = 'campaign_gototravel_is_back';
12628                    $campaignPageRecord = 'gototravel_is_back_record';
12629                    $campaignTerm = $goToTravelCampaign;
12630                }
12631            }
12632        } else if ($alvarkCollabCampaign) {
12633            if (!$counseling_flg) {
12634                $cst = ClassRegistry::init('CampaignSettingTable');
12635                $campaignStamps = $cst->alvarkCollaboration(
12636                    array(
12637                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12638                        'type' => 1,
12639                    )
12640                );
12641                $response['campaignStamps'] = $campaignStamps;
12642                $modalCampaignType = 'campaign_going_global_alvark_live';
12643                $campaignTerm = $alvarkCollabCampaign;
12644            }
12645        } 
12646
12647        if ($campaignSettings) {
12648            $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12649            $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12650            $showCampaignSettingsCampModal = array();
12651            foreach ($campaignSettings as $key => $value) {
12652                $id = $value['CampaignSettings']['id'];
12653                if (!in_array($id, $dontShowCampaignModals)) {
12654                    $showCampaignSettingsCampModal[] = $id;
12655                }
12656            }
12657            $response['campaignSettings'] = $campaignSettings;
12658            $response['showCampaignSettingsCampModal'] = $showCampaignSettingsCampModal;
12659            $response['campaignSettingsAfterLeson'] = true;
12660        } else if ($marinesCollabCampaign) {
12661            if (!$counseling_flg) {
12662                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12663                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12664                $marinesCollabCampPeriod = Configure::read('campaign_config.going_global_marines_collaboration.period');
12665                $marinesCollabCampaignSettingId = Configure::read('campaign_config.going_global_marines_collaboration.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12666    
12667                $response['marinesCollabCampaignSettingId'] = $marinesCollabCampaignSettingId;
12668                $response['marinesCollabCampaign'] = $marinesCollabCampaign;
12669                $response['showMarinesCollabCampModal'] = (!in_array($marinesCollabCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12670
12671                $cst = ClassRegistry::init('CampaignSettingTable');
12672                $campaignStamps = $cst->marinesCollaboration(
12673                    array(
12674                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12675                        'type' => 1,
12676                        'display_type' => 1,
12677                    )
12678                );
12679                $response['campaignStamps'] = $campaignStamps;
12680                $modalCampaignType = 'campaign_going_global_marines_live';
12681                $campaignTerm = $marinesCollabCampaign;
12682            }
12683        }
12684        // if ($dailyNewsCampaign) {
12685        //     if (!$counseling_flg) {
12686        //         $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12687        //         $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12688        //         $dailyNewsCampaignSettingId = Configure::read('campaign_config.daily_news.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12689
12690        //         $response['dailyNewsCampaignSettingId'] = $dailyNewsCampaignSettingId;
12691        //         $response['dailyNewsCampaign'] = $dailyNewsCampaign;
12692        //         $response['showDailyNewsCampModal'] = (!in_array($dailyNewsCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12693
12694        //         $cst = ClassRegistry::init('CampaignSettingTable');
12695        //         $campaignStamps = $cst->dailyNews(
12696        //             array(
12697        //                 'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12698        //                 'type' => 1
12699        //             )
12700        //         );
12701        //         $response['campaignStamps'] = $campaignStamps;
12702        //         $modalCampaignType = 'campaign_dailynews_live';
12703        //         $campaignTerm = $dailyNewsCampaign;
12704        //     }
12705        // }
12706
12707        if ($favoriteTeacherCampaign) {
12708            if (!$counseling_flg) {
12709                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12710                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12711                $favoriteTeacherCampaignSettingId = Configure::read('campaign_config.favorite_teacher.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12712
12713                $response['favoriteTeacherCampaignSettingId'] = $favoriteTeacherCampaignSettingId;
12714                $response['favoriteTeacherCampaign'] = $favoriteTeacherCampaign;
12715                $response['showFavoriteTeacherCampModal'] = (!in_array($favoriteTeacherCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12716
12717                $cst = ClassRegistry::init('CampaignSettingTable');
12718                $campaignStamps = $cst->favoriteTeacher(
12719                    array(
12720                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12721                        'type' => 1,
12722                        'requested_events' => array(1)
12723                    )
12724                );
12725                $response['campaignStamps'] = $campaignStamps['event1'];
12726                $modalCampaignType = 'campaign_favorite_teachers_live';
12727                $campaignTerm = $favoriteTeacherCampaign;
12728            }
12729        }
12730
12731        if ($familyPlanCampaign) {
12732            if (!$counseling_flg) {
12733                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12734                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12735                $familyPlanCampaignSettingId = Configure::read('campaign_config.family_plan.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12736
12737                $response['familyPlanCampaignSettingId'] = $familyPlanCampaignSettingId;
12738                $response['familyPlanCampaign'] = $familyPlanCampaign;
12739                $response['showFamilyPlanCampModal'] = (!in_array($familyPlanCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12740
12741                $cst = ClassRegistry::init('CampaignSettingTable');
12742                $lessonLogsFPC = $cst->familyPlan(
12743                    array(
12744                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12745                        'type' => 1
12746                    )
12747                );
12748                $response['lessonLogsFPC'] = $lessonLogsFPC;
12749                $modalCampaignType = 'campaign_plan_family_live';
12750                $campaignTerm = $familyPlanCampaign;
12751            }
12752        }
12753
12754        if ($christmasCampaign) {
12755            if (!$counseling_flg) {
12756                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12757                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12758                $christmasCampaignSettingId = Configure::read('campaign_config.christmas.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12759
12760                $response['christmasCampaignSettingId'] = $christmasCampaignSettingId;
12761                $response['christmasCampaign'] = $christmasCampaign;
12762                $response['showChristmasCampModal'] = (!in_array($christmasCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12763
12764                $cst = ClassRegistry::init('CampaignSettingTable');
12765                $lessonStamps = $cst->christmas(
12766                    array(
12767                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12768                        'type' => 1,
12769                    )
12770                );
12771                $response['lessonStamps'] = $lessonStamps;
12772                $modalCampaignType = 'campaign_christmas_live';
12773                $campaignTerm = $christmasCampaign;
12774            }
12775        }
12776
12777        if ($newYearPart1Campaign) {
12778            $campaignID = Configure::read('campaign_config.new_year_part_1.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_login');
12779            $lotteryData = array();
12780            $cst = ClassRegistry::init('CampaignSettingTable');
12781            $newYearLessonData = $cst->checkLastLesson(
12782                array(
12783                    'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12784                    'chat_hash' => $chat_hash,
12785                    'campaign_id' => $campaignID[0]
12786                )
12787            );
12788            $response['newYearPart1Campaign'] = $newYearPart1Campaign;
12789            $response['showNewYearPart1CampModal'] = ($newYearLessonData) ? true : false;
12790            $modalCampaignType = ($newYearLessonData) ? 'campaign_new_year_afterlesson' : '';
12791            $campaignTerm = $newYearPart1Campaign;
12792        }
12793
12794        if ($newGrammarCampaign) {
12795            if (!$counseling_flg) {
12796                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12797                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12798                $newGrammarCampaignSettingId = Configure::read('campaign_config.new_grammar.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12799    
12800                $response['newGrammarCampaignSettingId'] = $newGrammarCampaignSettingId;
12801                $response['newGrammarCampaign'] = $newGrammarCampaign;
12802                $response['showNewGrammarCampAfterLessonModal'] = (!in_array($newGrammarCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12803
12804                $cst = ClassRegistry::init('CampaignSettingTable');
12805                $campaignStamps = $cst->newGrammar(
12806                    array(
12807                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12808                        'type' => 1
12809                    )
12810                );
12811                $response['campaignStamps'] = $campaignStamps;
12812                $modalCampaignType = 'campaign_newgrammar_live';
12813                $campaignTerm = $newGrammarCampaign;
12814            }
12815        }
12816
12817        if ($alvarkCollab2Campaign) {
12818            if (!$counseling_flg) {
12819                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12820                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12821                $alvarkCollab2CampaignSettingId = Configure::read('campaign_config.alvark_collab_2.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12822    
12823                $response['alvarkCollab2CampaignSettingId'] = $alvarkCollab2CampaignSettingId;        
12824                $response['alvarkCollab2Campaign'] = $alvarkCollab2Campaign;
12825                $response['showAlvarkCollab2CampAfterLessonModal'] = (!in_array($alvarkCollab2CampaignSettingId, $dontShowCampaignModals)) ? true : false;    
12826
12827                $cst = ClassRegistry::init('CampaignSettingTable');
12828                $avk2coupon = $cst->alvarkCollab2(
12829                    array(
12830                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12831                        'type' => 1
12832                    )
12833                );
12834                $response['avk2coupon'] = $avk2coupon;
12835                $modalCampaignType = 'mypage_going_global_alvark_live';
12836                $campaignTerm = $alvarkCollab2Campaign;
12837            }
12838        }
12839
12840        if ($goldenWeekNCChallengeCampaign) {
12841            if (!$counseling_flg) {
12842                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12843                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12844                $campModalSettingIDs = Configure::read('campaign_config.golden_week_nc_challenge.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12845                $goldenWeekNCChallengeCampaignSettingId = ($memberType == 'student') ? $campModalSettingIDs['after_lesson'] : $campModalSettingIDs['after_live_lesson_viewer'];
12846
12847                $cst = ClassRegistry::init('CampaignSettingTable');
12848                $check = $cst->checkGoldenWeekChallengeModals(array(
12849                    'user_id' => $userData->id,
12850                    'chat_hash' => $chat_hash,
12851                    'camp_setting_id' => $goldenWeekNCChallengeCampaignSettingId
12852                ));
12853
12854                //Get stamp
12855                $goldenWeekNCChallengeStamp = $cst->goldenWeekChallenge(
12856                    array(
12857                        'user_id' => $userData->id,
12858                        'type' => 1,
12859                        'challenge_stamp' => ($memberType == 'student') ? 3 : 2
12860                    )
12861                );
12862
12863                $displayModalAfterLesson = (!in_array($goldenWeekNCChallengeCampaignSettingId, $dontShowCampaignModals) && $check) ? true : false;
12864                
12865                $response['goldenWeekNCChallengeStamp'] = $goldenWeekNCChallengeStamp;
12866                $response['goldenWeekNCChallengeCampaignSettingId'] = $goldenWeekNCChallengeCampaignSettingId;
12867                $response['goldenWeekNCChallengeCampaignAfterLesson'] = $goldenWeekNCChallengeCampaign;
12868                $response['showGoldenWeekNCChallengeCampAfterLessonModal'] = $displayModalAfterLesson;
12869
12870                $modalCampaignType = ($memberType == 'student') ? 'campaign_golden_week_lesson' : 'campaign_golden_week_live';
12871                $modalCampaignType = ($displayModalAfterLesson) ? $modalCampaignType : '';
12872                $campaignTerm = $goldenWeekNCChallengeCampaign;
12873            }
12874        }
12875
12876
12877        //NJ-21995 Super native camp festival campaign
12878        $superNativeCamp = array(
12879            'campaign' => 'super_native_camp',
12880            'user_membership' => $userData->getMembershipTypeIndex()
12881        );
12882        if(!$counseling_flg && $campaignSetting->campaignChecker($superNativeCamp)){
12883            $campModalSettingIDs = Configure::read('campaign_config.super_native_camp.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12884            $superNativeCampFestivalCampSettingID = $campModalSettingIDs['after_lesson'];
12885            $campaignTotalMinsOfLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 1));
12886            $checkCampaignLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 3, 'chat_hash' => $chat_hash));
12887            $displayModalAfterLesson = (!in_array($superNativeCampFestivalCampSettingID, $dontShowCampaignModals) && $checkCampaignLesson) ? true : false;;
12888            $response['campaignTotalMinsOfLesson'] = $campaignTotalMinsOfLesson;
12889            $response['superNativeCampFestivalCampSettingID'] = $superNativeCampFestivalCampSettingID;
12890            $response['showSuperNativeCampFestivalCampAfterLessonModal'] = $displayModalAfterLesson;
12891
12892            $modalCampaignType = 'campaign_nc_festival_live';
12893            $campaignTerm = true;
12894        }
12895
12896        //NJ-25217 Online English Conversation No.1 Festival
12897        $camp_OECF = array(
12898            'campaign' => 'OECF',
12899            'user_membership' => $userData->getMembershipTypeIndex(),
12900            'allow_language' => array(Configure::read('default.user_language'), 'en'),
12901            'user_language' => ($this->localizeDir == Configure::read('default.user_language') && in_array($userData->native_language2, array(Configure::read('default.user_language'), 'en'))) ? Configure::read('default.user_language') : $this->localizeDir,
12902            'user_currency' => $userData->currency_code,
12903            'allow_currency' => ($userData->native_language2 == 'en') ? array(Configure::read('default.user_currency')) : null
12904        );
12905        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_OECF)){
12906            $campModalSettingIDs = Configure::read('campaign_config.OECF.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12907            $camp_OECF_setting_ID = $campModalSettingIDs['after_lesson'][0];
12908            $dataStamp = $campaignSetting->onlineEnglishConversationFestival(array('user_id' => $userData->id, 'type' => 1, 'device' => 1));
12909            $displayModalAfterLesson = (!in_array($camp_OECF_setting_ID, $dontShowCampaignModals)) ? true : false;
12910            $response['dataStamp'] = $dataStamp;
12911            $response['OECFCampSettingID'] = $camp_OECF_setting_ID;
12912            $response['showOECFCampAfterLessonModal'] = $displayModalAfterLesson;
12913
12914            $modalCampaignType = 'campaign_nc_no1_festival_live';
12915            $campaignTerm = true;
12916        }
12917
12918        // - NJ-31307 Callan Unlimited Campaign
12919        $camp_callan_unlimited = array(
12920            'campaign' => 'callan_unlimited',
12921            'user_membership' => $userData->getMembershipTypeIndex()
12922        );
12923        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_callan_unlimited)){
12924            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12925            $displayModalAfterLesson = (!in_array($camp_callan_unlimited_ID, $dontShowCampaignModals)) ? true : false;
12926            if($displayModalAfterLesson){
12927                $modalCampaignType = 'campaign_callan_unlimited_afterlesson';
12928                $campaignTerm = true;
12929            }
12930        }
12931
12932        // - NJ-32989 : New Year Lottery Campaign
12933        $camp_new_year_lottery = array(
12934            'campaign' => 'new_year_lottery',
12935            'user_membership' => $userData->getMembershipTypeIndex(),
12936            'user_language' => $userData->native_language2,
12937            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
12938            'user_currency' => $userData->currency_code,
12939            'other_validation' => true,
12940        );
12941        if($campaignSetting->campaignChecker($camp_new_year_lottery)){
12942            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12943            $displayModalAfterLesson = (!in_array($camp_new_year_lottery_ID[0], $dontShowCampaignModals)) ? true : false;
12944            if($displayModalAfterLesson){
12945                $modalCampaignType = 'campaign_new_year_afterlesson';
12946                $campaignTerm = true;
12947            }
12948        }
12949
12950        // - NJ-32989 Around the world campaign
12951        $camp_around_the_world = array(
12952            'campaign' => 'around_the_world',
12953            'user_membership' => $userData->getMembershipTypeIndex(),
12954            'user_currency' => $userData->currency_code,
12955            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
12956            'user_language' => $userData->native_language2,
12957            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
12958        );
12959        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_around_the_world)){
12960            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
12961            $displayModalAfterLesson = (!in_array($camp_around_the_world_ID, $dontShowCampaignModals)) ? true : false;
12962            if($displayModalAfterLesson){
12963                $modalCampaignType = 'campaign_around_the_world_afterlesson';
12964                $campaignTerm = true;
12965            }
12966        }
12967
12968        // - NJ-36818 : What are you doing now? Native Camp! Campaign
12969        $camp_spare_time = array(
12970            'campaign' => 'spare_time_march',
12971            'user_membership' => $userData->getMembershipTypeIndex(),
12972            'user_language' => $userData->native_language2,
12973            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
12974        );
12975        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_spare_time)){
12976            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12977            $displayModalAfterLesson = (!in_array($camp_spare_time_ID, $dontShowCampaignModals)) ? true : false;
12978            if($displayModalAfterLesson){
12979                $modalCampaignType = 'campaign_spare_time_afterlesson';
12980                $campaignTerm = true;
12981            }
12982        }
12983
12984        // - NJ-39740 : 1.5 Million - Thank You Campaign
12985        $camp_opfm = array(
12986            'campaign' => 'OPFM_campaign',
12987            'user_membership' => $userData->getMembershipTypeIndex(),
12988            'user_language' => $userData->native_language2,
12989            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
12990        );
12991        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_opfm)){
12992            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12993            $displayModalAfterLesson = (!in_array($camp_opfm_ID, $dontShowCampaignModals)) ? true : false;
12994            if($displayModalAfterLesson){
12995                $modalCampaignType = 'campaign_150_ten_thousand_afterlesson';
12996                $campaignTerm = true;
12997            }
12998        }
12999
13000        // - NJ-42488 : kakaku_01 campaign
13001        $camp_kakaku01 = array(
13002            'campaign' => 'kakaku_01',
13003            'user_membership' => $userData->getMembershipTypeIndex(),
13004        );
13005        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_kakaku01)){
13006            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13007            if($userData->native_language2 == Configure::read('default.user_language')){
13008                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[0], $dontShowCampaignModals)) ? true : false;
13009                if($displayModalAfterLesson){
13010                    $modalCampaignType = 'campaign_kakaku_01_live';
13011                    $campaignTerm = true;
13012                }
13013            } else {
13014                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[1], $dontShowCampaignModals)) ? true : false;
13015                if($displayModalAfterLesson){
13016                    $modalCampaignType = 'campaign_dailynews_live';
13017                    $campaignTerm = true;
13018                }
13019            }
13020        }
13021
13022        // - NJ-45886 [Campaign] AI Speaking Campaign
13023        $camp_ai_speaking_sept = array(
13024            'campaign' => 'ai_speaking_sept',
13025            'user_membership' => $userData->getMembershipTypeIndex(),
13026            'user_language' => $userData->native_language2,
13027            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages'),
13028        );
13029        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_ai_speaking_sept)){
13030            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13031            $displayModalAfterLesson = (!in_array($camp_ai_speaking_sept_IDs[0], $dontShowCampaignModals)) ? true : false;
13032            if($displayModalAfterLesson){
13033                $modalCampaignType = 'campaign_speaking_afterlesson';
13034                $campaignTerm = true;
13035            }
13036        }
13037
13038        //NJ-50048 Lesson coin gift campaign
13039        $lessonCoinGiftCamp = array(
13040            'campaign' => 'taking_lesson_and_continue_plan',
13041            'user_membership' => $userData->getMembershipTypeIndex(),
13042            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13043            'user_language' => $userData->native_language2,
13044        );
13045        if(!$counseling_flg && $campaignSetting->campaignChecker($lessonCoinGiftCamp)){
13046            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13047            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13048            $displayModalAfterLesson = (!in_array($lessonCoinGiftCampSettingID, $dontShowCampaignModals)) ? true : false;
13049            if($displayModalAfterLesson){
13050                $modalCampaignType = 'campaign_lesson_coin_gift_live';
13051                $campaignTerm = true;
13052            }
13053        }
13054
13055        //NJ-55569 2025 New Year Campaign
13056        $newYearCamp = array(
13057            'campaign' => 'newyear_2025',
13058            'user_membership' => $userData->getMembershipTypeIndex(),
13059            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13060            'user_language' => $userData->native_language2,
13061            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13062            'user_currency' => $userData->currency_code,
13063        );
13064        if(!$counseling_flg && $campaignSetting->campaignChecker($newYearCamp)){
13065            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13066            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13067            if($userData->native_language2 == Configure::read('default.user_language')){
13068                $displayModalAfterLesson = (!in_array($newYearCampSettingID[0], $dontShowCampaignModals)) ? true : false;
13069                if($displayModalAfterLesson){
13070                    $modalCampaignType = 'campaign_new_year_live';
13071                    $campaignTerm = true;
13072                }
13073            } else {
13074                $displayModalAfterLesson = (!in_array($newYearCampSettingID[1], $dontShowCampaignModals)) ? true : false;
13075                if($displayModalAfterLesson){
13076                    $modalCampaignType = 'campaign_dailynews_live';
13077                    $campaignTerm = true;
13078                }
13079            }
13080        }
13081
13082        //NJ-59889 3 Million Campaign
13083        $threeMillionCamp = array(
13084            'campaign' => '3_million',
13085            'user_membership' => $userData->getMembershipTypeIndex(),
13086            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13087            'user_language' => $userData->native_language2,
13088            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13089            'user_currency' => $userData->currency_code,
13090        );
13091        if(!$counseling_flg && $campaignSetting->campaignChecker($threeMillionCamp)){
13092            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13093            $displayModalAfterLesson = (!in_array($threeMillionCampSettingId, $dontShowCampaignModals)) ? true : false;
13094            if($displayModalAfterLesson){
13095                $modalCampaignType = 'campaign_3_million_afterlesson';
13096                $campaignTerm = true;
13097            }
13098        }
13099
13100        // - NJ-65066 【Campaign】Daily Topics
13101        $dailytopicsCamp = array(
13102            'campaign' => 'daily_topics',
13103            'user_membership' => $userData->getMembershipTypeIndex(),
13104            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13105            'user_language' => $userData->native_language2,
13106            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13107            'user_currency' => $userData->currency_code,
13108        );
13109        if(!$counseling_flg && $campaignSetting->campaignChecker($dailytopicsCamp)){
13110            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13111            $displayModalAfterLesson = (!in_array($dailytopicsCampSettingId, $dontShowCampaignModals)) ? true : false;
13112            if($displayModalAfterLesson){
13113                $modalCampaignType = 'campaign_dailytopics_afterlesson';
13114                $campaignTerm = true;
13115            }
13116        }
13117
13118        $response['campaign_name'] = $modalCampaignType;
13119        $response['campaignPageRecord'] = $campaignPageRecord;
13120        $response['campaignTerm'] = $campaignTerm;
13121
13122        return $response;
13123    }
13124
13125
13126    //Retrieves the active campaign stamp data for the authenticated user in Native Camp. It checks various campaigns and sets the campaign data for the view.
13127    public function getActiveCampaignStampData($params = []) {
13128
13129        $usrObj = new UserTable($this->sharedUserData['User']);
13130        $cst_ = ClassRegistry::init('CampaignSettingTable');
13131
13132        // - NJ-31307 Callan unlimited campaign
13133        $camp_callan_unlimited = array(
13134            'campaign' => 'callan_unlimited',
13135            'user_membership' => $usrObj->getMembershipTypeIndex()
13136        );
13137        if($cst_->campaignChecker($camp_callan_unlimited)){
13138            $campaignStamp = $cst_->callanUnlimitedCampaign(array(
13139                'trigger' => 1,
13140                'user_id' => $usrObj->id
13141            ));
13142            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13143            $this->set('campaignStamp', $campaignStamp);
13144            $this->set('callanUnlimitedSettingID', $camp_callan_unlimited_ID);
13145            $this->set('showCallanUnlimitedAfterLessonModal', true);
13146        }
13147
13148        // - NJ-32989 : New Year Lottery Campaign
13149        $camp_new_year_lottery = array(
13150            'campaign' => 'new_year_lottery',
13151            'user_membership' => $usrObj->getMembershipTypeIndex(),
13152            'user_language' => $usrObj->native_language2,
13153            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
13154            'user_currency' => $usrObj->currency_code,
13155            'other_validation' => true,
13156        );
13157        if($cst_->campaignChecker($camp_new_year_lottery)){
13158            $campaignLotteryTicket = $cst_->newYearLotteryCamp(array(
13159                'trigger' => 1,
13160                'user_id' => $usrObj->id
13161            ));
13162            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13163            $this->set('campaignLotteryTicket', $campaignLotteryTicket);
13164            $this->set('newYearLotterySettingID', $camp_new_year_lottery_ID[0]);
13165            $this->set('showNewYearLotteryAfterLessonModal', true);
13166        }
13167
13168        // - NJ-32989 Around the world campaign
13169        $camp_around_the_world = array(
13170            'campaign' => 'around_the_world',
13171            'user_membership' => $usrObj->getMembershipTypeIndex(),
13172            'user_currency' => $usrObj->currency_code,
13173            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
13174            'user_language' => $usrObj->native_language2,
13175            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
13176
13177        );
13178        if($cst_->campaignChecker($camp_around_the_world)){
13179            $stampData = ClassRegistry::init('CampaignSettingTable')->aroundTheWorldCamp(['user_id' => $usrObj->id, 'trigger' => 1]);
13180            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
13181            $this->set('aroundTheWorldSettingID', $camp_around_the_world_ID);
13182            $this->set('showAroundTheWorldAfterLessonModal', true);
13183            $this->set('total_stamp_count', $stampData['total_count'] ?? 0 );
13184            $this->set('stamp_html', $stampData['stamp_html'] ?? '' );
13185        }
13186
13187        // - NJ-36818 : What are you doing now? Native Camp! Campaign
13188        $camp_spare_time = array(
13189            'campaign' => 'spare_time_march',
13190            'user_membership' => $usrObj->getMembershipTypeIndex(),
13191            'user_language' => $usrObj->native_language2,
13192            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
13193        );
13194        if($cst_->campaignChecker($camp_spare_time)){
13195            $campaignStamp = $cst_->spareTimeCampaign(array(
13196                'trigger' => 1,
13197                'user_id' => $usrObj->id
13198            ));
13199            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13200            $this->set('spareTimeCampaignStamp', $campaignStamp);
13201            $this->set('spareTimeSettingID', $camp_spare_time_ID);
13202            $this->set('showSpareTimeAfterLessonModal', true);
13203        }
13204
13205        // 1.5 Million - Thank You Campaign
13206        $camp_opfm = array(
13207            'campaign' => 'OPFM_campaign',
13208            'user_membership' => $usrObj->getMembershipTypeIndex(),
13209            'user_language' => $usrObj->native_language2,
13210            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
13211        );
13212        if($cst_->campaignChecker($camp_opfm)){
13213            $campaignStamp = $cst_->opfmCampaign(array(
13214                'trigger' => 1,
13215                'user_id' => $usrObj->id
13216            ));
13217            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13218            $this->set('opfmCampaignStamp', $campaignStamp);
13219            $this->set('opfmSettingID', $camp_opfm_ID);
13220            $this->set('showOpfmAfterLessonModal', true);
13221        }
13222
13223        // - NJ-42488 : kakaku_01 campaign
13224        $camp_kakaku01 = array(
13225            'campaign' => 'kakaku_01',
13226            'user_membership' => $usrObj->getMembershipTypeIndex()
13227        );
13228        if($cst_->campaignChecker($camp_kakaku01)){
13229            $kakakuCampaignStamp = ClassRegistry::init('CampaignSettingTable')->kakaku01_camp(array(
13230                'trigger' => 1,
13231                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13232            ));
13233            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13234            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13235                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13236                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[0]);
13237                $this->set('showKakaku01AfterLessonModal', true);
13238            } else {
13239                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13240                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[1]);
13241                $this->set('showKakaku01DailyNewsAfterLessonModal', true);
13242            }
13243        }
13244
13245        // - NJ-42488 : kakaku_01 campaign
13246        $camp_ai_speaking_sept = array(
13247            'campaign' => 'ai_speaking_sept',
13248            'user_membership' => $usrObj->getMembershipTypeIndex(),
13249            'user_language' => $usrObj->native_language2,
13250            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages')
13251        );
13252        if($cst_->campaignChecker($camp_ai_speaking_sept)){
13253            $aiSpeakingSeptCampaignStamp = ClassRegistry::init('CampaignSettingTable')->ai_speaking_camp(array(
13254                'trigger' => 1,
13255                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13256            ));
13257            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13258            $this->set('aiSpeakingSeptCampaignStamp', $aiSpeakingSeptCampaignStamp);
13259            $this->set('aiSpeakingSeptSettingID', $camp_ai_speaking_sept_IDs[0]);
13260            $this->set('showAISpeakingSeptAfterLessonModal', true);
13261        }
13262
13263        //NJ-50048 Lesson coin gift campaign
13264        $lessonCoinGiftCamp = array(
13265            'campaign' => 'taking_lesson_and_continue_plan',
13266            'user_membership' => $usrObj->getMembershipTypeIndex(),
13267            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13268            'user_language' => $usrObj->native_language2,
13269        );
13270        if($cst_->campaignChecker($lessonCoinGiftCamp)){
13271            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13272            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13273            $dataStamp = $cst_->takingLessonAndContinuePlan(array('user_id' => $usrObj->id, 'type' => 1, 'device' => 1));
13274            $this->set('dataStamp', $dataStamp);
13275            $this->set('lessonCoinGiftCampSettingID', $lessonCoinGiftCampSettingID);
13276            $this->set('showLessonCoinGiftCampAfterLessonModal', true);
13277        }
13278
13279        //NJ-55569 2025 New Year Campaign
13280        $newYearCamp = array(
13281            'campaign' => 'newyear_2025',
13282            'user_membership' => $usrObj->getMembershipTypeIndex(),
13283            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13284            'user_language' => $usrObj->native_language2,
13285            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13286            'user_currency' => $usrObj->currency_code,
13287        );
13288        if($cst_->campaignChecker($newYearCamp)){
13289            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13290            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13291            $newyear2025_stamp = $cst_->newyear2025_camp(array('user_id' => $usrObj->id, 'trigger' => 1));
13292            $this->set('newyear2025_stamp', $newyear2025_stamp);
13293
13294            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13295                $this->set('showNewYearCampAfterLessonModal', true);
13296                $this->set('newYearCampSettingID', $newYearCampSettingID[0]);
13297            } else {
13298                $this->set('showNewYearDailyNewsCampAfterLessonModal', true);
13299                $this->set('newYearCampSettingID', $newYearCampSettingID[1]);
13300            }
13301        }
13302
13303        //NJ-59889 3 Million Campaign
13304        $threeMillionCamp = array(
13305            'campaign' => '3_million',
13306            'user_membership' => $usrObj->getMembershipTypeIndex(),
13307            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13308            'user_language' => $usrObj->native_language2,
13309            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13310            'user_currency' => $usrObj->currency_code,
13311        );
13312        if($cst_->campaignChecker($threeMillionCamp)){
13313            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13314            $campaignStamp = $cst_->threeMillionCamp([
13315                'trigger' => 1,
13316                'user_id' => $usrObj->id,
13317                'lang' => $this->localizeDir
13318            ]);
13319            $this->set( 'threeMillionCampaignStamp', $campaignStamp );
13320            $this->set('showthreeMillionCampAfterLessonModal', true);
13321            $this->set('threeMillionCampSettingId', $threeMillionCampSettingId);
13322        }
13323
13324        // - NJ-65066 【Campaign】Daily Topics
13325        $dailytopicsCamp = array(
13326            'campaign' => 'daily_topics',
13327            'user_membership' => $usrObj->getMembershipTypeIndex(),
13328            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13329            'user_language' => $usrObj->native_language2,
13330            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13331            'user_currency' => $usrObj->currency_code,
13332        );
13333        if($cst_->campaignChecker($dailytopicsCamp)){
13334            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13335            $campaignStamp = $cst_->dailyTopics([
13336                'trigger' => 1,
13337                'user_id' => $usrObj->id,
13338                'lang' => $this->localizeDir
13339            ]);
13340            $this->set( 'dailytopicsCampaignStamp', $campaignStamp );
13341            $this->set('showdailytopicsCampAfterLessonModal', true);
13342            $this->set('dailytopicsCampSettingId', $dailytopicsCampSettingId);
13343        }
13344        
13345        $this->set('userToken', $this->Auth->user('api_token'));
13346    }
13347
13348
13349    //Determines whether to show the campaign modal based on the current date and the provided start and end dates.
13350    public function showCampaignModal($startDate = null, $endDate = null){
13351        if(!empty($startDate) && !empty($endDate)){
13352            $current_date = strtotime('now');
13353            $showCampaignModal = $current_date >= strtotime($startDate) && $current_date <= strtotime($endDate) ? true : false;
13354
13355            return $showCampaignModal;
13356        }
13357
13358        return false;
13359    }
13360
13361    /**
13362     * @api {post} /user/waiting/generateTextbookTeacherRecommendAjax generateTextbookTeacherRecommendAjax()
13363     * @apiName generateTextbookTeacherRecommendAjax
13364     * @apiGroup Waiting
13365     * @apiDescription Generates a list of recommended teachers for a specific textbook in Native Camp. It retrieves the teacher recommendations based on the user's last lesson and textbook data.
13366     *
13367     * @apiBody {String} category_id The ID of the textbook category.
13368     * @apiBody {String} connect_id The ID of the textbook connect.
13369     * @apiBody {String} teacher_id The ID of the teacher.
13370     * 
13371     * @apiSuccess {Number} result Indicates whether the operation was successful.
13372     * @apiSuccess {String} html The HTML content for the recommended teachers modal.
13373     *
13374     * @apiSuccessExample {json} Success-Response:
13375     *     {
13376     *         "result": 1,
13377     *         "html": "<div>Recommended Teachers</div>"
13378     *     }
13379     *
13380     * @apiError {Number} result Indicates whether the operation was successful.
13381     * @apiError {String} html The HTML content for the recommended teachers modal.
13382     *
13383     * @apiErrorExample {json} Error-Response:
13384     *     {
13385     *         "result": 0,
13386     *         "html": ""
13387     *     }
13388     * 
13389     * @apiSampleRequest off
13390     */
13391    public function generateTextbookTeacherRecommendAjax() {
13392        $this->autoRender = false;
13393        $this->layout = false;
13394        $resultSuccess = 0;
13395        $resultHTML = '';
13396        $isSubmittedFiveStar = 0;
13397        if ($this->request->is('ajax')) {
13398
13399            $curDate = date('Y-m-d');
13400            $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
13401            $txtTeacherRecommendlimit = 3; // modal limit
13402            $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
13403            $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
13404            $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
13405            $categoryId = isset($this->request->data['category_id']) ? $this->request->data['category_id'] : null;
13406            $connectId = isset($this->request->data['connect_id']) ? $this->request->data['connect_id'] : null;
13407            $teacherId = isset($this->request->data['teacher_id']) ? $this->request->data['teacher_id'] : null;
13408            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13409
13410            if( $userId ) {
13411
13412
13413                // - NJ-8416: check for last lesson type
13414                $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
13415                $this->log('[NJ-8416 lastLessonType lessonFinish] -> ' . json_encode($lastLessonType), 'debug');
13416                $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
13417                        'user_id' => $userId,
13418                        'connect_id' => $connectId,
13419                        'limit' => 3, // modal
13420                        'last_lesson_type' => $lastLessonType
13421                    ) 
13422                );
13423
13424                $textbookCategoryId = $lastBookUsedData['category_id'];
13425                $textbookBadge = $lastBookUsedData['textbook_badge'];
13426                $this->log('[NJ-8416 textbookCategoryId lessonFinish] -> ' . json_encode($textbookCategoryId), 'debug');
13427                $paramsArr = array(
13428                    'user_id' => $userId,
13429                    'begin_date' => $beginDate,
13430                    'end_date' => $endDate,
13431                    'textbook_category' => $textbookCategoryId,
13432                    'textbook_badge' => $textbookBadge,
13433                    'limit' => $txtTeacherRecommendlimit,
13434                    'user_data' => $userData,
13435                    'exclude_teacher_id' => $teacherId
13436                );
13437
13438                $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
13439                if( $teacherTextbookStatData ) {
13440                    $dataList = $this->arrangeTeacherRecommendList( array( 
13441                            'user_id' => $userId,
13442                            'data' => $teacherTextbookStatData,
13443                            'category_id' => $textbookCategoryId,
13444                            'user_data' => $userData
13445                        )
13446                    );
13447
13448                    $this->set('textbookTeacherData', $dataList);
13449                    $view = new View($this, false);
13450                    $resultHTML = $view->element( 'lesson_finish_textbook_teacher_list_modal', array(
13451                            'textbookTeacherData' => isset($dataList) && $dataList ? $dataList : array()
13452                        )
13453                    );
13454                    $resultSuccess = 1;
13455                }
13456
13457                //- NJ-61019: get rating from mecached
13458                if($chatHash && $chatHash != 'hash') {
13459                    if (!class_exists('myMemcached')) {
13460                        App::uses('myMemcached', 'Lib');
13461                    }
13462                    $memcached = new myMemcached();
13463                    $rate = $memcached->get("rating_".$chatHash);
13464
13465                    if(isset($rate) && $rate == 5) {
13466                        $isSubmittedFiveStar = 1;
13467                    }
13468                }
13469            }
13470
13471        }
13472        return json_encode(array(
13473            'result' => $resultSuccess,
13474            'html' => $resultHTML,
13475            'isSubmittedFiveStar' => $isSubmittedFiveStar
13476        ));
13477    }
13478
13479    /**
13480    * Ajax Request : fetch user's appreciation options data for modal display
13481    */
13482    //not used function
13483    public function setUpAppreciationSelectionModalElementAjax() {
13484        $this->autoRender = false;
13485        $this->layout = false;
13486        $result = array();
13487        if ($this->request->is('ajax')) {
13488            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13489            if($chatHash){
13490                $fetchParam = array( 'chat_hash'  => $chatHash );
13491                $fetchedData = $this->setUpAppreciationSelectionModalElement($fetchParam);
13492                if( isset( $fetchedData['html_element'] ) && $fetchedData['html_element'] ){
13493                    $result['html_element'] = $fetchedData['html_element'];
13494                }
13495            }
13496        }
13497        return json_encode(array(
13498            'result' => $result
13499        ));
13500    }
13501
13502    /**
13503    * Ajax Request : Send teacher's appreciation
13504    */
13505    //not used function
13506    public function sendTeacherAppreciationAjax() {
13507        $this->autoRender = false;
13508        $this->layout = false;
13509        $result = array( 'result' => 0 );
13510        $teacherAppreciationMessage = "";
13511        $teacherAppreciationAmount = 0;
13512        $hasTips = 1;
13513        $hasMessage = 1;
13514        $noMessageText = '';
13515        $noTipsText = '';
13516
13517        if ($this->request->is('ajax')) {
13518            $appreciationId = isset($this->request->data['appreciation_ration_input']) ? $this->request->data['appreciation_ration_input'] : null;
13519            $message = isset($this->request->data['user_comment_text']) ? trim($this->request->data['user_comment_text']) : null;
13520            $chatHash = isset($this->request->data['chat_hash_input']) ? $this->request->data['chat_hash_input'] : null;
13521            $actionMode = isset($this->request->data['action_mode']) ? $this->request->data['action_mode'] : 0;
13522            
13523            // - initialize api tunnel
13524            myTools::initializeApiTunnel(array('AppreciationController'));    
13525            $params = array(
13526                "users_api_token" => $this->Auth->user('api_token'),
13527                'chat_hash' => $chatHash,
13528                'appreciation_id'  => $appreciationId,
13529                'message' => $message,
13530                'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
13531
13532            );
13533            $api = new AppreciationController();
13534            $api->params = $params;
13535            
13536            // - send teacher appreciation
13537            $sendData = $api->send();
13538
13539            // - Detect prohibited words in teacher appreciation messages sent after class.
13540            $this->ProhibitedWord->detectProhibitedWordOnStudentAppreciation([
13541                'chat_hash' => $chatHash,
13542                'message' => $message,
13543            ]);
13544            
13545            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13546                // set default res
13547                $result = array( 'result' => 1 );
13548
13549                // set return appreciation item
13550                $appreciationDetails = $sendData['appreciation_item'];
13551
13552            } else {
13553                if( isset ($sendData['error'] ) && $sendData['error'] ){
13554                    $result['error']['id'] = 'sending_failed';
13555                    $result['error']['message'] = json_encode($sendData['error']);
13556                }
13557            }
13558
13559            // set appreciation details student message
13560            if(empty($appreciationDetails['student_message'])){
13561                $appreciationDetails['student_message'] = __d('modal','このお礼にメッセージはありません。');
13562                $appreciationDetails['student_message_flg'] = false;
13563            }else{
13564                $appreciationDetails['student_message_flg'] = true;
13565            }
13566
13567            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13568                $teacherAppreciationMessage = $appreciationDetails['message'];
13569                $teacherAppreciationAmount = $appreciationDetails['amount'];
13570
13571                if(empty($appreciationId)) {
13572                    // no apprecation tips form
13573                    $hasTips = 0;
13574                    if($appreciationId != 0)  {
13575                        $hasTips = 0;
13576                    }
13577                    $noTipsText = __d('modal','チップはありません');
13578                }
13579
13580                if (empty($message)) {
13581                    // no appreciation message form
13582                    $hasMessage = 0;
13583                    $noMessageText = __d('modal','メッセージはありません');
13584                }
13585
13586                $result = array( 'result' => 1 );
13587
13588                if ($actionMode == 1) {
13589                    $hasTips = 1;
13590                    $hasMessage = 1;
13591                }
13592
13593            } else {
13594                if( isset ($sendData['error'] ) && $sendData['error'] ){
13595                    $result['error']['id'] = 'sending_failed';
13596                    $result['error']['message'] = json_encode($sendData['error']);
13597                    if(isset($sendData['error']['error_code'])) {
13598                        $result['error']['error_code'] = json_encode($sendData['error']['error_code']);
13599                    }
13600                }
13601            }    
13602
13603        }
13604        return json_encode(array(
13605            'output' => $result,
13606            'appreciation_message' => $teacherAppreciationMessage,
13607            'appreciation_amount' => $teacherAppreciationAmount,
13608            'has_tips' => $hasTips,
13609            'has_message' => $hasMessage,
13610            'appreciation_details' => $appreciationDetails,
13611            'no_message_text' => $noMessageText,
13612            'no_tips_text' => $noTipsText
13613        ));
13614    }
13615
13616
13617    /**
13618    * ajax set after lesson evaluate system problem
13619    */
13620    //not used function
13621    public function ajaxUpdateSystemTrouble() {
13622        $this->autoRender = false;
13623        $this->layout = false;
13624        $troubleResponse = false;
13625        if ($this->request->is('ajax')) {
13626            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13627            $status = isset($this->request->data['value']) ? $this->request->data['value'] : 0;
13628            $lesson = $this->LessonOnairsLog->findByChatHash($chatHash, array('LessonOnairsLog.id'),null, -1);
13629            if (isset($lesson) && $lesson) {
13630                if (isset($lesson['LessonOnairsLog']['id']) && $lesson['LessonOnairsLog']['id']) {
13631                    if($this->LessonOnairsLog->read(null, $lesson['LessonOnairsLog']['id'])){
13632                        $this->LessonOnairsLog->saveField('lesson_system_trouble', $status);
13633                    }
13634                    $troubleResponse = true;
13635                }
13636            } 
13637        }
13638        return json_encode(array(
13639            'result' => $troubleResponse
13640        ));
13641    }
13642
13643    /**
13644     * @api {post} /user/waiting/reportProblem reportProblem()
13645     * @apiName reportProblem
13646     * @apiGroup Waiting
13647     * @apiDescription Reports a problem during a lesson in Native Camp. It updates the lesson status and sends a notification to Slack.
13648     *
13649     * @apiBody {String} problem The description of the problem.
13650     * @apiBody {String} chatHash The chat hash of the lesson.
13651     * @apiBody {String} [member_type] The type of the member (viewer or student).
13652     * 
13653     * @apiSuccess {Boolean} success Indicates whether the operation was successful.
13654     *
13655     * @apiSuccessExample {json} Success-Response:
13656     *     {
13657     *         "success": true
13658     *     }
13659     *
13660     * @apiError {Boolean} success Indicates whether the operation was successful.
13661     *
13662     * @apiErrorExample {json} Error-Response:
13663     *     {
13664     *         "success": false
13665     *     }
13666     * 
13667     * @apiSampleRequest off
13668     */
13669    public function reportProblem() {
13670        $this->autoRender = false;
13671        $this->layout = false;
13672
13673        if ($this->Auth->loggedIn() && isset($this->request->data['problem']) && isset($this->request->data['chatHash'])) {
13674            //get data
13675            $problem = $this->request->data['problem'];
13676            $chatHash = $this->request->data['chatHash'];
13677            $userId = $this->Auth->user('id');
13678            $memberType = isset($this->request->data['member_type']) ? $this->request->data['member_type'] : 'student';
13679
13680            if ($memberType == 'viewer') {
13681                //-live_system_trouble
13682                $res = $this->LessonOnairsViewer->updateAll(
13683                    array(
13684                        'LessonOnairsViewer.live_system_trouble' => 1
13685                    ),
13686                    array(
13687                        'LessonOnairsViewer.user_id' => $userId,
13688                        'LessonOnairsViewer.chat_hash' => $chatHash
13689                    )
13690                );
13691                return json_encode(array('success' => ($res?true:false)));
13692            }
13693
13694            $lessonData = LessonOnairTable::findLessonData(array(
13695                'fields' => array(
13696                    'id',
13697                    'teacher_id',
13698                    'user_id',
13699                    'chat_hash',
13700                    'lesson_system_trouble',
13701                    'user_agent'
13702                ),
13703                'conditions' => array(
13704                    'chat_hash' => $chatHash,
13705                    'user_id' => $userId
13706                )
13707            ));
13708
13709            //if no lesson data found
13710            if (!$lessonData) {
13711                return json_encode(array('success' => false));
13712            } elseif ($lessonData['data']['lesson_system_trouble'] == 0) {
13713                //update trouble
13714                $model = ClassRegistry::init($lessonData['model']);
13715                if ($model->read(null, $lessonData['data']['id'])) {
13716                    $model->set('lesson_system_trouble', 1);
13717                    $model->save();
13718                }
13719            }            
13720
13721            //fetch data
13722            $finalData = $lessonData['data'];
13723            $finalData['user_name'] = $this->Auth->user('nickname');
13724
13725            //query teacher name
13726            $teacherData = $this->Teacher->find('first', array(
13727                'fields' => 'name',
13728                'conditions' => array('Teacher.id' => $finalData['teacher_id']),
13729                'recursive' => -1
13730            ));
13731
13732            //set teacher name
13733            $finalData['teacher_name'] = isset($teacherData['Teacher']['name']) ? $teacherData['Teacher']['name'] : ''; 
13734
13735            //fetch problem data
13736            $problemData = $this->LessonOnairsLog->countProblematicLesson(array(
13737                'userId' => $userId,
13738                'teacherId' => $finalData['teacher_id'],
13739                'lessonData' => $lessonData['data']
13740            ));
13741
13742            // send to slack
13743            $slack = new mySlack();
13744            // set the channel, change to #nc-monitoring
13745            $slack->channel  = myTools::checkChannel("#nc-voice-trouble", "#nc-voice-trouble-dev");
13746            //type
13747            $slack->text = "```種別:通信トラブル(PC)\n";
13748            // set os and problem count
13749            $slack->text .= "本日:{$problemData['totalProblemCount']}件目({$problemData['userAgentStr']})\n";
13750            // set lecturer id and number of lesson
13751            $slack->text .= "講師ID:{$finalData['teacher_id']} ({$finalData['teacher_name']})(本日{$problemData['teacherCount']}回目)\n";
13752            // set member id and number of lesson
13753            $slack->text .= "会員ID:{$userId} ({$finalData['user_name']})(本日{$problemData['userCount']}回目)\n";
13754            // set contents
13755            $slack->text .= "内容:{$problem}\n";
13756            // set chat hash
13757            $slack->text .= "chathash: https://{$_SERVER['HTTP_HOST']}/admin/lesson-history?chat_hash={$chatHash}" . '```';
13758            // set slack user name
13759            $slack->username = "NativeCamp";
13760
13761            // send slack
13762            $resp = $slack->sendSlack(); //returns http code
13763            if ($resp) {
13764                return json_encode(array('success' => true));
13765            }
13766        }
13767        return json_encode(array('success' => false));
13768    }
13769
13770    /**
13771     * @api {post} /user/waiting/getApppreciationModal getApppreciationModal()
13772     * @apiName getApppreciationModal
13773     * @apiGroup Waiting
13774     * @apiDescription Retrieves the appreciation modal data for a specific lesson in Native Camp. It checks the appreciation status and returns the appreciation data.
13775     *
13776     * @apiBody {String} chat_hash The chat hash of the lesson.
13777     * @apiBody {String} member_type The type of the member (viewer or student).
13778     * 
13779     * @apiSuccess {Boolean} error Indicates whether there was an error.
13780     * @apiSuccess {String} [error_msg] The error message (if any).
13781     * @apiSuccess {String} [appreciation_data] The HTML element for the appreciation data.
13782     * @apiSuccess {Boolean} [appreciation_done] Indicates whether the appreciation is done.
13783     *
13784     * @apiSuccessExample {json} Success-Response:
13785     *     {
13786     *         "error": false,
13787     *         "appreciation_data": "<div>Appreciation Data</div>",
13788     *         "appreciation_done": true
13789     *     }
13790     *
13791     * @apiError {Boolean} error Indicates whether there was an error.
13792     * @apiError {String} error_msg The error message.
13793     *
13794     * @apiErrorExample {json} Error-Response:
13795     *     {
13796     *         "error": true,
13797     *         "error_msg": "An error occurred."
13798     *     }
13799     * 
13800     * @apiSampleRequest off
13801     */
13802    public function getApppreciationModal() {
13803        $this->autoRender = false;
13804        $this->layout = false;
13805
13806        if ($this->request->is('ajax')) {
13807            $response = array();
13808            $data = $this->request->data;
13809
13810            try  {
13811                if (!empty($data['member_type']) && $data['member_type'] !== 'viewer') {
13812                    // Check appreciation data
13813                    $appreciationElementData = $this->setUpAppreciationSelectionModalElement( array( 'chat_hash' => $data['chat_hash'] ) );
13814                    if(!empty($appreciationElementData['html_element'])){
13815                        $response['appreciation_data'] = $appreciationElementData['html_element'];
13816                    }
13817                    $elapsed5mins = false;
13818                    // 5mins elapsed only
13819                    $lessonExists = $this->LessonOnairsLog->isLessonEnded($data['chat_hash']);
13820                    if ($lessonExists) {
13821                        $this->LessonOnairsLog->openDBReplica();
13822                        $created = $this->LessonOnairsLog->find('first', [
13823                            'fields' => ['created'],
13824                            'conditions' => ['chat_hash' => $data['chat_hash']]
13825                        ]);
13826                        $this->LessonOnairsLog->closeDBReplica();
13827                        if (!empty($created)){
13828                            $created = $created['LessonOnairsLog']['created'];
13829                            $now = date('Y-m-d H:i:s');
13830                            $elapsed5mins = ( strtotime($now) - strtotime($created)) > 300;
13831                        }
13832                    }
13833                    $response['has_elapsed'] = $elapsed5mins;
13834                    $response['appreciation_done'] = $this->getAppreciationStatus($data['chat_hash']);
13835                    $response['error'] = false;
13836                }
13837                return json_encode($response);
13838                
13839            } catch (Exception $e) {
13840                $response['error'] = true;
13841                $response['error_msg'] = $e->getMessage();
13842
13843                 // - add logger
13844                 $mySlack = new mySlack();
13845                 $mySlack->channel = myTools::checkChannel("#fdci-irregular-monitoring");
13846                 $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
13847                 $mySlack->username = "GetAppreciationModalFailed";
13848                 $mySlack->text = "```";
13849                 $mySlack->text .= "Message : ". $e->getMessage() ."\n";
13850                 $mySlack->text .= "Chat-hash: ". $data['chat_hash'] ."\n";
13851                 $mySlack->text .= "Student ID: ". $this->Auth->user('id') ."\n";
13852                 $mySlack->text .= "UA: ". $_SERVER['HTTP_USER_AGENT'] ."\n";
13853                 $mySlack->text .= "referrer: ". $_SERVER['HTTP_REFERER'] ."\n";
13854                 $mySlack->text .= "```";
13855                 // - send slack message
13856                 $mySlack->sendSlack();
13857                return json_encode($response);
13858            }
13859        }
13860    }
13861
13862    private function getAppreciationStatus($chatHash) {
13863        $doneAppreciation = false;
13864        $appreFields = array(
13865            'TeacherCoinBox.has_tips',
13866            'TeacherCoinBox.done_flg'
13867        );
13868        $checkCoinBoxData = $this->TeacherCoinBox->getData(array('chat_hash' => $chatHash), $appreFields);
13869        if(
13870            $checkCoinBoxData && 
13871            (isset($checkCoinBoxData['TeacherCoinBox']['has_tips']) && $checkCoinBoxData['TeacherCoinBox']['has_tips']) ||
13872            (isset($checkCoinBoxData['TeacherCoinBox']['done_flg']) && $checkCoinBoxData['TeacherCoinBox']['done_flg'])
13873        ) {
13874            $doneAppreciation = true;
13875        }
13876
13877        return $doneAppreciation;
13878    }
13879
13880    /**
13881     * @api {post} /user/waiting/getEvaluationDetail getEvaluationDetail()
13882     * @apiName getEvaluationDetail
13883     * @apiGroup Waiting
13884     * @apiDescription Retrieves the evaluation detail for a specific lesson in Native Camp. It checks if the user has already submitted an evaluation for the lesson.
13885     *
13886     * @apiBody {String} chat_hash The chat hash of the lesson.
13887     * @apiBody {String} [member_type] The type of the member (viewer or student).
13888     * 
13889     * @apiSuccess {Boolean} status Indicates whether the evaluation has been submitted.
13890     *
13891     * @apiSuccessExample {json} Success-Response:
13892     *     {
13893     *         "status": true
13894     *     }
13895     *
13896     * @apiError {String} error Message indicating the error.
13897     *
13898     * @apiErrorExample {json} Error-Response:
13899     *     {
13900     *         "error": "Invalid request."
13901     *     }
13902     * 
13903     * @apiSampleRequest off
13904     */
13905    public function getEvaluationDetail() {
13906        $this->autoRender = false;
13907        $this->layout = false;
13908        $doneReview['status'] = false;
13909        if ($this->request->is('ajax')) {
13910            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13911            //-check if viewer
13912            if (isset($this->request->data['member_type']) && $this->request->data['member_type'] == 'viewer') {
13913                $eval = $this->ViewersClassEvaluation->find('first', [
13914                    'conditions' => [
13915                        'ViewersClassEvaluation.user_id' => $this->Auth->user('id'),
13916                        'ViewersClassEvaluation.chat_hash' => $chatHash
13917                    ]
13918                ]);
13919                $doneReview['status'] = !empty($eval);        
13920            } else {
13921                if ($this->UsersClassEvaluation->findByChatHash($chatHash)) {
13922                    $doneReview['status'] = true;
13923                }
13924            }
13925        }
13926        return json_encode($doneReview);
13927    }
13928    /**
13929     * @api {post} /user/waiting/resetLessonReviewModal resetLessonReviewModal()
13930     * @apiName resetLessonReviewModal
13931     * @apiGroup Waiting
13932     * @apiDescription Resets the lesson review modal status for a specific lesson and user in Native Camp. It deletes the modal status from the cache.
13933     *
13934     * @apiBody {String} chatHash The chat hash of the lesson.
13935     * @apiBody {String} userId The ID of the user.
13936     * 
13937     * @apiSuccess {Boolean} res Indicates whether the operation was successful.
13938     *
13939     * @apiSuccessExample {json} Success-Response:
13940     *     {
13941     *         "res": true
13942     *     }
13943     *
13944     * @apiError {String} error Message indicating the error.
13945     *
13946     * @apiErrorExample {json} Error-Response:
13947     *     {
13948     *         "error": "Invalid request."
13949     *     }
13950     * 
13951     * @apiSampleRequest off
13952     */
13953    public function resetLessonReviewModal() {
13954        $this->autoRender = false;
13955        $this->layout = false;
13956        if ($this->request->is('ajax')) {
13957            $chatHash = $this->request->data('chatHash');
13958            $userId = $this->request->data('userId');
13959            $memcached = new myMemcached();
13960            $modalStatus = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $userId);
13961            if ($modalStatus !== false) {
13962                $memcached->delete('lesson-review-modal-' . $chatHash .'-'. $userId);
13963            }
13964        }
13965        echo json_encode(array('res' => true));
13966    }
13967
13968    /**
13969     * @api {post} /user/waiting/finishOnlineLesson finishOnlineLesson()
13970     * @apiName finishOnlineLesson
13971     * @apiGroup Waiting
13972     * @apiDescription Finishes an online lesson for the authenticated user in Native Camp. It retrieves lesson details, updates lesson status, and returns the lesson summary.
13973     *
13974     * @apiBody {String} chatHash The chat hash of the lesson.
13975     * 
13976     * @apiSuccess {Boolean} lessonHistoryExist Indicates whether the lesson history exists.
13977     * @apiSuccess {String} ageRange The age range of the user.
13978     * @apiSuccess {Object} logDetail The lesson log details.
13979     * @apiSuccess {Object} lessonOnAirData The lesson on-air data.
13980     * @apiSuccess {Object} teacherDetailData The teacher detail data.
13981     * @apiSuccess {Object} teacherData The teacher data.
13982     * @apiSuccess {Array} avatarTeacherIdArr The array of avatar teacher IDs.
13983     * @apiSuccess {String} teacherName The name of the teacher.
13984     * @apiSuccess {String} teacherNameJA The Japanese name of the teacher.
13985     * @apiSuccess {String} teacherImage The image URL of the teacher.
13986     * @apiSuccess {String} urlLink The URL link to the teacher's detail page.
13987     * @apiSuccess {String} favTeaherId The favorite teacher ID.
13988     * @apiSuccess {String} counselorImageUrl The image URL of the counselor.
13989     * @apiSuccess {String} textbookImage The image URL of the textbook.
13990     * @apiSuccess {String} courseTitle The title of the course.
13991     * @apiSuccess {String} subCategoryLabel The label of the subcategory.
13992     * @apiSuccess {String} chapterTitle The title of the chapter.
13993     * @apiSuccess {Boolean} lessonTrouble Indicates whether there was a lesson trouble.
13994     * @apiSuccess {String} userToken The user token.
13995     * @apiSuccess {Object} finishLessonUser The user data.
13996     * @apiSuccess {String} chat_hash The chat hash of the lesson.
13997     * @apiSuccess {Boolean} lesson_review_flg Indicates whether the lesson review flag is set.
13998     * @apiSuccess {Boolean} isDefaulTextbook Indicates whether the textbook is the default textbook.
13999     * @apiSuccess {Boolean} firstSelectedDummy Indicates whether the first selected textbook is a dummy.
14000     * @apiSuccess {Boolean} allowEvaluation Indicates whether the teacher evaluation is allowed.
14001     * @apiSuccess {Object} getActiveCampaign The active campaign data.
14002     * @apiSuccess {Boolean} firstLesson Indicates whether it is the first lesson.
14003     * @apiSuccess {Boolean} hideTextbookChangeModal Indicates whether to hide the textbook change modal.
14004     * @apiSuccess {String} textbookCategoryType The type of the textbook category.
14005     * @apiSuccess {String} memberType The type of the member.
14006     * @apiSuccess {String} nickname The nickname of the user.
14007     * @apiSuccess {Number} textbookCategoryId The ID of the textbook category.
14008     * @apiSuccess {Number} isLiveFlg Indicates whether the lesson is live.
14009     * @apiSuccess {Boolean} lessonReviewModalOn Indicates whether the lesson review modal is on.
14010     * @apiSuccess {String} user_language The language of the user.
14011     *
14012     * @apiSuccessExample {json} Success-Response:
14013     *     {
14014     *         "lessonHistoryExist": true,
14015     *         "ageRange": "20-30",
14016     *         "logDetail": {...},
14017     *         "lessonOnAirData": {...},
14018     *         "teacherDetailData": {...},
14019     *         "teacherData": {...},
14020     *         "avatarTeacherIdArr": [...],
14021     *         "teacherName": "John Doe",
14022     *         "teacherNameJA": "ジョン・ドウ",
14023     *         "teacherImage": "http://example.com/image.jpg",
14024     *         "urlLink": "/waiting/detail/1",
14025     *         "favTeaherId": "1",
14026     *         "counselorImageUrl": "http://example.com/counselor.jpg",
14027     *         "textbookImage": "http://example.com/textbook.jpg",
14028     *         "courseTitle": "Course Title",
14029     *         "subCategoryLabel": "Subcategory Label",
14030     *         "chapterTitle": "Chapter Title",
14031     *         "lessonTrouble": false,
14032     *         "userToken": "example_token",
14033     *         "finishLessonUser": {...},
14034     *         "chat_hash": "example_chat_hash",
14035     *         "lesson_review_flg": 1,
14036     *         "isDefaulTextbook": false,
14037     *         "firstSelectedDummy": false,
14038     *         "allowEvaluation": 1,
14039     *         "getActiveCampaign": {...},
14040     *         "firstLesson": false,
14041     *         "hideTextbookChangeModal": "false",
14042     *         "textbookCategoryType": "Type",
14043     *         "memberType": "student",
14044     *         "nickname": "nickname",
14045     *         "textbookCategoryId": 1,
14046     *         "isLiveFlg": 0,
14047     *         "lessonReviewModalOn": false,
14048     *         "user_language": "en"
14049     *     }
14050     *
14051     * @apiError {String} error Message indicating the error.
14052     *
14053     * @apiErrorExample {json} Error-Response:
14054     *     {
14055     *         "error": "Invalid request."
14056     *     }
14057     * 
14058     * @apiSampleRequest off
14059     */
14060    public function finishOnlineLesson() {
14061        $this->autoRender = false;
14062        $this->layout = false;
14063        if ($this->request->is('ajax')) {
14064            $chatHash = $this->request->data('chatHash');
14065        
14066            // 4372 textbook name cached
14067            $memcached = new myMemcached();
14068            $textbookNamesCached = $memcached->get(Configure::read('textbook_names_cache_key'));
14069
14070            $userId = $this->Auth->user('id');
14071            $this->Session->delete('lesson.proceedFlg');
14072            //CheckHash
14073            $this->LessonOnairsLog->openDBReplica();
14074            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
14075            $lessonHistoryExist = true;
14076            $this->LessonOnairsLog->closeDBReplica();
14077            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
14078                $this->LessonOnair->openDBReplica();
14079                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
14080                $lessonHistoryExist = false;
14081                $this->LessonOnair->closeDBReplica();
14082                if(!$allData) {
14083                    die();
14084                }
14085            }
14086
14087            $response['lessonHistoryExist'] = $lessonHistoryExist;
14088            $userValidForSSBEDT = false;
14089            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14090                $userValidForSSBEDT = true;
14091            }
14092
14093            $param = array( 
14094                "user_id" => $userId,
14095                "select_method" => "first",
14096                "env_flag" => "all",
14097                'connect_id' => $allData['Connect']['id'],
14098                "user_locale" => $this->localizeDir,
14099                "userValidForSSBEDT" => $userValidForSSBEDT
14100            );
14101            $textbookData = $this->Textbook->getTextbooks($param);
14102            
14103            $lessonUserData = (isset($allData['User'])) ? new UserTable($allData['User']) : null;
14104            
14105            $response['ageRange'] = $lessonUserData->getAgeRange();
14106            $response['logDetail'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14107            if(isset($allData['LessonOnairsLog'])) {
14108                $response['lessonOnAirData'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14109
14110            } else if(isset($allData['LessonOnair'])) {
14111                $response['lessonOnAirData'] = new LessonOnairTable($allData['LessonOnair']);
14112            } else {
14113                $response['lessonOnAirData'] = null;
14114            }
14115            $teacherData = new TeacherTable($allData['teacher']);
14116            $response['teacherDetailData'] = new TeacherDetailTable($allData['TeacherDetail']);
14117            
14118            $response['teacherData'] = $teacherData;
14119            $response['avatarTeacherIdArr'] = Configure::read("default_avatar_detail");
14120            $response['teacherName'] = $teacherData->name;
14121            $response['teacherNameJA'] = $teacherData->jp_name;
14122            $response['teacherImage'] = $teacherData->getImageUrl();
14123            $response['urlLink'] = "/waiting/detail/".$teacherData->getId();
14124            $response['favTeaherId'] = $teacherData->id;
14125            if ($teacherData->counseling_flg) {
14126                $counselorImageUrl = $teacherData->getProfileImage(Configure::read('default_counselor_detail'));
14127                $response['counselorImageUrl'] = $counselorImageUrl;
14128                $response['teacherName'] = "Counselor";
14129                $response['teacherNameJA'] = "カウンセラー";
14130                $response['teacherImage'] = $counselorImageUrl['image_url'];
14131                $response['urlLink'] = "/counselor_detail";
14132            }
14133            // avatar teacher
14134            if ($teacherData->avatar_id && $teacherData->avatar_flg) {
14135                if ($teacherData->avatar_id) {
14136                    $response['teacherName'] = $teacherData->getAvatarParentNameEn();
14137                    $response['teacherNameJA'] =  $teacherData->getAvatarParentName();
14138                    $response['teacherImage'] = $teacherData->getAvatarParentImageUrl();
14139                    $response['favTeaherId'] = $teacherData->avatar_id;
14140                    $response['urlLink'] = "/avatar_detail/".$teacherData->avatar_id;
14141                }
14142            }
14143
14144            $data = $textbookData['res_data'];
14145            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14146
14147            //- check if for live viewing
14148            $onairData = isset($allData['LessonOnairsLog']) ? $allData['LessonOnairsLog'] : $allData['LessonOnair'];
14149            $onAirUserId = $onairData['user_id'];
14150            $isLive = $onairData['live_lesson_flg'];
14151
14152            //- check member type
14153            $memberType = 'student';
14154            $liveSystemTrouble = 0;
14155
14156            if ($isLive && $onAirUserId != $userId) {
14157                $memberType = 'viewer';
14158                //- update end time
14159                $this->LessonOnairsViewersLog->endTime([
14160                    'chat_hash'     => $chatHash,
14161                    'user_id'         => $userId,
14162                    'guest_viewer'     => empty($userId) ? 1 : 0,
14163                    'viewer_ip'         => myTools::getClientIP()
14164                ]);
14165
14166                $liveLog = $this->LessonOnairsViewer->find('first', [
14167                    'fields' => [
14168                        'LessonOnairsViewer.live_system_trouble'
14169                    ],
14170                    'conditions' => [
14171                        'LessonOnairsViewer.user_id' => $userId,
14172                        'LessonOnairsViewer.chat_hash' => $chatHash
14173                    ]
14174                ]);
14175                $liveSystemTrouble = (!empty($liveLog['LessonOnairsViewer']['live_system_trouble'])) ? 1 : 0;
14176
14177                if ($liveLog) {
14178                    // process live lesson coupon grant
14179                    $this->LessonOnairsViewer->processLiveLessonCouponGrant($this->sharedUserData['User'], $chatHash);
14180                }
14181            }
14182
14183            $userValidForSSBEDT = false;
14184            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14185                $userValidForSSBEDT = true;
14186            }
14187            $param = array(
14188                "user_id" => $userId,
14189                "select_method" => "first",
14190                "env_flag" => "all",
14191                'connect_id' => $allData['Connect']['id'],
14192                "user_locale" => $this->localizeDir,
14193                "userValidForSSBEDT" => $userValidForSSBEDT
14194            );
14195            //NJ-12326
14196            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
14197                $corporateParams = array('user_id' => $userId);
14198                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
14199
14200                if ($corporateTextbookControlFlg == 1) {
14201                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
14202                    if (!empty($categoryData)) {
14203                        $param['include_kids_category'] = $allData['Connect']['category_id'];
14204                    }
14205                }
14206            }
14207            $textbookData = $this->Textbook->getTextbooks($param);
14208
14209            $data = $textbookData['res_data'];
14210
14211            // textbook image
14212            $response['textbookImage'] = $data['TextbookCategory']['image_small_url'];
14213
14214            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14215            
14216            $courseTitle = (isset($data['TextbookCategory']['name'])) ? $data['TextbookCategory']['name'] : '';
14217            $subCategoryNameLabel = (isset($data['TextbookSubcategory']['name'])) ? $data['TextbookSubcategory']['name'] : '';
14218            $chapterTitle = isset($textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] ) ?  $textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] : ((isset($data['Textbook']['name'])) ? $order.$data['Textbook']['name'] : '');
14219
14220            #global textbook information
14221            $globalCourseTitle = isset($data['GlobalTextbookCategory']['gl_name']) ? $data['GlobalTextbookCategory']['gl_name'] : $courseTitle;
14222            $subCategoryNameLabel = isset($data['GlobalTextbookSubcategory']['gl_name']) ? $data['GlobalTextbookSubcategory']['gl_name'] : $subCategoryNameLabel;
14223            $globalChapterTitle = isset($data['GlobalTextbook']['gl_name']) ? $order.$data['GlobalTextbook']['gl_name'] : $chapterTitle;
14224
14225            // check for main topic
14226            if ( isset($data['Textbook']['main_topic_id']) && $data['Textbook']['main_topic_id'] ) {
14227                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
14228                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($data['Textbook']['id'],$langId);
14229                if ($textbookMainTopicName) {
14230                    $subCategoryNameLabel = $textbookMainTopicName;
14231                }
14232            }
14233
14234            //get teacher id from logs
14235            $teacherId = isset($allData['LessonOnairsLog']['teacher_id']) ? $allData['LessonOnairsLog']['teacher_id'] : $allData['LessonOnair']['teacher_id']; 
14236
14237            // - check if the queried data has teacher rank coin id
14238            if(isset($allData['teacher']['rank_coin_id'])) {
14239                $teacher_rank_coin_id = $allData['teacher']['rank_coin_id'];
14240
14241            } else {
14242                // - get teacher rank coin id
14243                $this->Teacher->openDBReplica();
14244                $coinId = $this->Teacher->find('first',array(
14245                    'fields' => array('Teacher.rank_coin_id'),
14246                    'conditions' => array('Teacher.id' => $teacherId),
14247                    'recursive' => -1
14248                ));
14249                $this->Teacher->closeDBReplica();
14250                $teacher_rank_coin_id = isset($coinId['Teacher']['rank_coin_id']) ? $coinId['Teacher']['rank_coin_id'] :  null;
14251
14252            }
14253
14254            $showRatingFlg = $this->TeacherRankCoin->find('first',array(
14255                    'fields' => array('TeacherRankCoin.strength_weakness_flag', 'TeacherRankCoin.id'),
14256                    'conditions' => array('TeacherRankCoin.id' => $teacher_rank_coin_id)
14257                ));
14258            $response['showRatingFlg'] = $showRatingFlg['TeacherRankCoin']['strength_weakness_flag'];
14259
14260            $user = (isset($this->sharedUserData['User'])) ? new UserTable($this->sharedUserData['User']) : null;
14261            $response['userMembershipIndex'] = null;
14262            if (!empty($user)) {
14263                $userMembershipIndex = $user->getMembershipTypeIndex();
14264                $response['userMembershipIndex'] = $userMembershipIndex;
14265            }            
14266
14267            $noNextTextbookModal = array(
14268                11, //'Corporate Limited Plan(Company payment-Bank transfer)'
14269                35, //'Study Sapuri ENGLISH School Plan (Paid)',
14270                16, //'Corporate Light Plan(Company payment-Bank transfer)',
14271                25, //'Corporate Light Plan (Company payment-Card)',
14272                17, //'Corporate Light Plan (Individual payment)',
14273            );
14274
14275            $response['noNextTextbookModal'] = $noNextTextbookModal;
14276
14277            $counselorDetail = $this->Teacher->getDefaultCounselorDetail();
14278            $this->set('counselorDetail', $counselorDetail);
14279
14280            if (is_null($allData['teacher']['first_lesson_date'])) {
14281                if (isset($allData['LessonOnair'])) {
14282                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnair']['end_time'];
14283                } elseif (isset($allData['LessonOnairsLog'])) {
14284                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnairsLog']['end_time'];
14285                }
14286            }
14287
14288            //NC-4572
14289            $userID = $this->Auth->user('id');
14290
14291            $lessonTrouble = isset($allData['LessonOnairsLog']['lesson_system_trouble']) ? intval($allData['LessonOnairsLog']['lesson_system_trouble']) : intval($allData['LessonOnair']['lesson_system_trouble']); 
14292
14293            $response['lessonTrouble'] =  ($lessonTrouble || $liveSystemTrouble);
14294            $response['userToken'] = $this->Auth->user('api_token');
14295            $response['courseTitle'] = $globalCourseTitle;
14296            $response['subCategoryLabel'] = $subCategoryNameLabel;
14297            $response['chapterTitle'] = $globalChapterTitle;
14298            $response['finishLessonUser'] = $user;
14299            $response['chat_hash'] = $chatHash;
14300            $response['lesson_review_flg'] = isset($user->lesson_review_flg) ? $user->lesson_review_flg : 0;
14301
14302            // NJ-8416
14303            $env = Configure::read('ENVIRONMENT');
14304            $defaultTextbookId = Configure::read("default_dummy_textbook.{$env}");
14305            $dummyConnectId = Configure::read("dummy_textbook_connect_id.{$env}");
14306
14307            // - check end lesson textbook is dummy
14308            $isDefaulTextbook = ($defaultTextbookId == $allData['Connect']['category_id']) ? true : false;
14309
14310            $response['isDefaulTextbook'] = $isDefaulTextbook;
14311
14312            // - get first selected textbook connect_id
14313            $userFirstSelectedTextbook = $this->User->getUserData(
14314                array(
14315                    'id' => $userId
14316                ),
14317                array(
14318                    'first_selected_textbook'
14319                ),
14320                'first'
14321            );
14322
14323            // - check first selected textbook connect_id is dummy
14324            $firstSelectedDummy = ($userFirstSelectedTextbook['User']['first_selected_textbook'] == $dummyConnectId) ? true : false;
14325            $response['firstSelectedDummy'] = $firstSelectedDummy;
14326
14327
14328            // NJ-33170
14329            $lessonConnectId = isset($allData['LessonOnairsLog']['connect_id']) && $allData['LessonOnairsLog']['connect_id'] ? $allData['LessonOnairsLog']['connect_id'] : $allData['LessonOnair']['connect_id'];
14330            // get lesson textbook category id
14331            $this->TextbookConnect->openDbReplica();
14332            $textbookConnect = $this->TextbookConnect->find('first', array(
14333                'fields' => array('TextbookConnect.category_id'),
14334                'conditions' => array('TextbookConnect.id' => $lessonConnectId)
14335            ));
14336            $this->TextbookConnect->closeDbReplica();
14337            $lessonTextbookCategoryId = isset($textbookConnect['TextbookConnect']['category_id']) ? $textbookConnect['TextbookConnect']['category_id'] : null;
14338            
14339            $teacherEvalRestrictedTextbook = Configure::read("teacher_evaluation_restricted_textbook.{$env}");
14340            // disable teacher textbook evaluation if textbook is: (Textbook selection after entering the lesson)
14341            $allowEvaluation = $lessonTextbookCategoryId == $teacherEvalRestrictedTextbook ? 0 : 1;
14342
14343            $response['allowEvaluation'] = $allowEvaluation;
14344
14345            // [START]--- Campaign modal
14346            $getActiveCampaignParams = array(
14347                'counseling_flg' => isset($allData['teacher']['counseling_flg']) ? $allData['teacher']['counseling_flg'] : 0,
14348                'avatar_flg' => isset($allData['teacher']['avatar_flg']) ? $allData['teacher']['avatar_flg'] : 0,
14349                'chat_hash' => $chatHash,
14350                'memberType' => $memberType
14351            );
14352            $response['getActiveCampaign'] = $this->getActiveCampaign($getActiveCampaignParams);
14353            // [ END ]--- Campaign modal
14354
14355            // NC-7922 sapuri first lesson
14356            if ($this->studySapuriId) {
14357                $firstLesson = $this->UserFirstLesson->checkFirstLesson(array('user_id' => $userID));
14358                if ($firstLesson && $firstLesson['UserFirstLesson']['chat_hash'] == $chatHash) {
14359                    $oUserData = new UserTable($this->sharedUserData['User']);
14360                    $sapuriPlan = $oUserData->isStudySapuri();
14361                    $stusapTextType = Configure::read('studysapuri_textbook_category_types');
14362                    $topList = $this->CommonTeacherStatus->getSapuriRecommendTeacher($stusapTextType[$sapuriPlan]);
14363                    $firstLesson = true;
14364
14365                    $response['reserveRecommend'] = $topList;
14366                } else {
14367                    $firstLesson = false;
14368                }
14369            } else {
14370                $firstLesson = false;
14371            }
14372
14373            $response['firstLesson'] = $firstLesson;
14374
14375            // NC-7592 - Hide textbookChange modal after lesson if reserved lesson & disable button if no next textbook chapter
14376            $isReservedLesson = 2;
14377            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
14378            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
14379
14380            //NJ-3626 Optimize PC /lesson-finish page
14381            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
14382            $lessonOnairLatestDataFlg = false;
14383            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
14384                $lessonOnairLatestDataFlg = true;
14385                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
14386                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
14387            } else {
14388                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userID, $teacherId);
14389                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
14390                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
14391                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
14392                }
14393            }
14394
14395            // - initialize empty variable
14396            $isLatestPresetTextbookMadeDuringLastLesson = [];
14397            $latestPresetTextbookParams = [];
14398
14399            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
14400            if ($lessonOnairLatestDataFlg) {
14401                $latestPresetTextbookParams = array (
14402                    'userId' => $userID,
14403                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14404                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
14405                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
14406                );
14407
14408            // - if has lesson onairs log
14409            } else if ($lessonOnairLogsLatestData) {
14410                $latestPresetTextbookParams = array (
14411                    'userId' => $userID,
14412                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14413                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
14414                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
14415                );
14416
14417            }
14418
14419            $response['isStudySapuriTosUser'] = $this->isStudySapuriTosUser;
14420            // - if has parameters for fetching latest textbook parameters
14421            if ($latestPresetTextbookParams) {
14422                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
14423            }
14424
14425            // -  check sapuri ID
14426            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
14427                if (isset($lessonOnairLatestDataFlg)) {
14428                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14429                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
14430                    ) {
14431                        $hideTextbookChangeModal = 'true';
14432                    }
14433                } else {
14434                    if (
14435                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14436                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
14437                    ) {
14438                        $hideTextbookChangeModal = 'true';
14439                    }
14440                }
14441            }
14442            
14443            // NJ-3696
14444            if($lessonHistoryExist) {
14445                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnairsLog']['textbook_category_id']);
14446            } else {
14447                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnair']['textbook_category_id']);
14448            }
14449
14450            //TODO: NJ-59368 - send is callan textbook category
14451            $response['isCallanTextbook'] = in_array($response['textbookCategoryType'], Configure::read('callan_textbook_type'));
14452
14453            $response['hideTextbookChangeModal'] = $hideTextbookChangeModal;
14454
14455            $response['memberType'] = $memberType;
14456            $response['nickname'] = isset($this->sharedUserData['User']['nickname']) ? $this->sharedUserData['User']['nickname'] : $this->Auth->user('nickname');
14457            $response['textbookCategoryId'] = (int)$allData['Connect']['category_id'];
14458            $response['isLiveFlg'] = (int)$isLive;
14459            $response['lessonReviewModalOn'] = false;
14460            $response['network_review_flg'] = $this->sharedUserData['User']['network_review_flg']; // include the user's setting 'network_review_flg' in the response
14461            if ($this->Auth->User('id')) {
14462                $reviewLessonCache = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $this->Auth->User('id'));
14463                if ($reviewLessonCache !== false && $reviewLessonCache == 1) {
14464                    $response['lessonReviewModalOn'] = true;
14465                }
14466            }
14467            $response['user_language'] = $this->localizeDir;
14468            return json_encode($response);
14469        }
14470        
14471    }
14472
14473    /**
14474     * @api {post} /user/waiting/getCounselorLessonHistory getCounselorLessonHistory()
14475     * @apiName getCounselorLessonHistory
14476     * @apiGroup Waiting
14477     * @apiDescription Retrieves the lesson history for a specific counselor in Native Camp. It returns the lesson history details including textbook information, lesson time, and URLs for chat logs and message logs.
14478     *
14479     * @apiBody {String} teacherId The ID of the teacher.
14480     * 
14481     * @apiSuccess {Boolean} res Indicates whether the request was successful.
14482     * @apiSuccess {Array} lessonHistory The lesson history details.
14483     * @apiSuccess {String} lessonHistory.lesson_number The lesson number.
14484     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in Japanese format.
14485     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
14486     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson in minutes.
14487     * @apiSuccess {String} lessonHistory.textbook_url The URL for the textbook details.
14488     * @apiSuccess {String} lessonHistory.categoryNameLabel The label for the category name.
14489     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The label for the subcategory name.
14490     * @apiSuccess {String} lessonHistory.textbookNameLabel The label for the textbook name.
14491     * @apiSuccess {Number} lessonHistory.rate The rating for the lesson.
14492     * @apiSuccess {String} lessonHistory.chat_logs_url The URL for the chat logs.
14493     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates whether the lesson has message logs.
14494     * @apiSuccess {String} lessonHistory.message_logs_url The URL for the message logs.
14495     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
14496     * @apiSuccess {String} lessonHistory.textbook_image The URL for the textbook image.
14497     *
14498     * @apiSuccessExample {json} Success-Response:
14499     *     {
14500     *         "res": true,
14501     *         "lessonHistory": [
14502     *             {
14503     *                 "lesson_number": "1",
14504     *                 "chatStartJPDate": "2023-01-01",
14505     *                 "chatStartTime": "10:00",
14506     *                 "lessonHistoryTime": "30分",
14507     *                 "textbook_url": "/textbook/page-detail/1/1",
14508     *                 "categoryNameLabel": "Category Name",
14509     *                 "subCategoryNameLabel": "Subcategory Name",
14510     *                 "textbookNameLabel": "Textbook Name",
14511     *                 "rate": 5,
14512     *                 "chat_logs_url": "/chat-history/1/1",
14513     *                 "has_message_logs": true,
14514     *                 "message_logs_url": "/lesson-message/detail/1",
14515     *                 "audio_count_log": 1,
14516     *                 "textbook_image": "http://example.com/image.jpg"
14517     *             },
14518     *             ...
14519     *         ]
14520     *     }
14521     *
14522     * @apiError {Boolean} res Indicates whether the request was successful.
14523     *
14524     * @apiErrorExample {json} Error-Response:
14525     *     {
14526     *         "res": false
14527     *     }
14528     * 
14529     * @apiSampleRequest off
14530     */
14531    public function getCounselorLessonHistory() {
14532        $this->autoRender = false;
14533        $this->layout = false;
14534        $response = json_encode(array('res' => false)); // default
14535        
14536        if($this->request->is('post')) {
14537            $post = $this->request->data;
14538            if (!isset($post['teacherId']) && $post['teacherId']) {
14539                return json_encode($response);
14540            }
14541            $teacherId = $post['teacherId'] ?? null;
14542
14543            //NC-7984 start
14544            $lesson_history_data = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), 10);
14545            if(!empty($lesson_history_data) && $lesson_history_data) {
14546                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
14547
14548                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
14549                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
14550                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
14551
14552                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
14553
14554                    $lessonTime = $dteStart->diff($dteEnd);
14555                    $lessonHistoryTime = $lessonTime->format("%I");
14556
14557                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
14558
14559                    $categoryName = $value['TextbookCategory']['name'];
14560                    $subcategoryName = $value['TextbookSubategory']['name'];
14561                    $textbookName = $value['Textbook']['name'];
14562                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
14563
14564                    // - if has translated Category name
14565                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
14566                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
14567                    }
14568
14569                    // - if has translated subcategory name
14570                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
14571                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
14572                    }
14573
14574                    // - if has translated textbook name
14575                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
14576                        $textbookName = $value['GlobalTextbook']['gl_name'];
14577                    }
14578
14579                    // - set textbook name
14580                    $categoryNameLabel = $categoryName;
14581                    $subCategoryNameLabel = $subcategoryName;
14582                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
14583                    $textbookNameLabel = $textbookOrder . $textbookName;
14584                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
14585
14586                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
14587                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
14588                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
14589                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
14590
14591                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
14592                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
14593                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
14594                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
14595                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
14596                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
14597                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
14598                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
14599                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
14600                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
14601                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
14602                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
14603                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
14604                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
14605                }
14606                
14607                $response = json_encode(array(
14608                    'res' => true, 
14609                    'lessonHistory' => $lesson_history_data['lessonHistory']
14610                ));
14611            }
14612        }
14613        return $response;
14614    }
14615
14616    /**
14617     * @api {get} /user/waiting/speakingTestAttendance speakingTestAttendance()
14618     * @apiName speakingTestAttendance
14619     * @apiGroup Waiting
14620     * @apiDescription Retrieves the attendance status for the speaking test and counseling sessions for the authenticated user in Native Camp. It returns the URLs, CSS classes, and text for the speaking test and counseling status.
14621     * 
14622     * @apiSuccess {String} speakingTestDailyFlgUrl The URL for the daily speaking test.
14623     * @apiSuccess {String} speakingTestBusinessFlgUrl The URL for the business speaking test.
14624     * @apiSuccess {String} speakingTestDailyFlgClass The CSS class for the daily speaking test status.
14625     * @apiSuccess {String} speakingTestBusinessFlgClass The CSS class for the business speaking test status.
14626     * @apiSuccess {String} counselingFlgClass The CSS class for the counseling status.
14627     * @apiSuccess {String} speakingTestDailyFlgTxt The text for the daily speaking test status.
14628     * @apiSuccess {String} speakingTestBusinessFlgTxt The text for the business speaking test status.
14629     * @apiSuccess {String} counselingFlgTxt The text for the counseling status.
14630     *
14631     * @apiSuccessExample {json} Success-Response:
14632     *     {
14633     *         "speakingTestDailyFlgUrl": "http://example.com/en/speaking_test/daily_start",
14634     *         "speakingTestBusinessFlgUrl": "http://example.com/en/speaking_test/business_start",
14635     *         "speakingTestDailyFlgClass": "",
14636     *         "speakingTestBusinessFlgClass": "",
14637     *         "counselingFlgClass": "",
14638     *         "speakingTestDailyFlgTxt": "未受験",
14639     *         "speakingTestBusinessFlgTxt": "未受験",
14640     *         "counselingFlgTxt": "未受講"
14641     *     }
14642     *
14643     * @apiError {String} error Message indicating the error.
14644     *
14645     * @apiErrorExample {json} Error-Response:
14646     *     {
14647     *         "error": "Invalid request."
14648     *     }
14649     * 
14650     * @apiSampleRequest off
14651     */
14652    public function speakingTestAttendance(){
14653        $this->autoRender = false;
14654        $this->layout = false;
14655
14656        $speakingTestDailyFlgUrl         = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/daily_start";
14657        $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/business_start";
14658        $speakingTestDailyFlgClass         = '';
14659        $speakingTestBusinessFlgClass     = '';
14660        $counselingFlgClass             = '';
14661        $speakingTestDailyFlgTxt         = __d('waiting', '未受験');
14662        $speakingTestBusinessFlgTxt     = __d('waiting', '未受験');
14663        $counselingFlgTxt                 = __d('waiting', '未受講');
14664
14665        $monthlySpeakingTestStatus = array();
14666        if ( $this->request->is('ajax') && !empty($this->sharedUserData['User']['id']) ) {
14667            $monthlySpeakingTestStatus = UserTable::monthlySpeakingTrainingStatus(array(
14668                'user_id' => $this->sharedUserData['User']['id'],
14669                'time_diff' => $this->timeDiffSecond
14670            ));
14671            //-- Speaking training daily
14672            if (!empty($monthlySpeakingTestStatus['speaking_test_daily_english_flg'])) {
14673                $speakingTestDailyFlgClass         = 'done';
14674                $speakingTestDailyFlgUrl         = myTools::getUrl().'/'.$this->localizeDir. "/speaking_test/daily_start?result=true";
14675                $speakingTestDailyFlgTxt = __d('waiting', '受験済み');
14676            }
14677            //-- Speaking training business
14678            if (!empty($monthlySpeakingTestStatus['speaking_test_business_english_flg'])) {
14679                $speakingTestBusinessFlgClass     = 'done';
14680                $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir."/speaking_test/business_start?result=true";
14681                $speakingTestBusinessFlgTxt = __d('waiting', '受験済み');
14682            }
14683            //-- Counseling
14684            if (!empty($monthlySpeakingTestStatus['counseling_lesson_flg'])) {
14685                $counselingFlgClass = 'done';
14686                $counselingFlgTxt = __d('waiting', '受講済み');
14687            }
14688
14689            $monthlySpeakingTestStatus = array(
14690                'speakingTestDailyFlgUrl'         => $speakingTestDailyFlgUrl,
14691                'speakingTestBusinessFlgUrl'     => $speakingTestBusinessFlgUrl,
14692                'speakingTestDailyFlgClass'     => $speakingTestDailyFlgClass,
14693                'speakingTestBusinessFlgClass'     => $speakingTestBusinessFlgClass,
14694                'counselingFlgClass'             => $counselingFlgClass,
14695                'speakingTestDailyFlgTxt'         => $speakingTestDailyFlgTxt,
14696                'speakingTestBusinessFlgTxt'     => $speakingTestBusinessFlgTxt,
14697                'counselingFlgTxt'                 => $counselingFlgTxt
14698            );
14699        }
14700        return json_encode($monthlySpeakingTestStatus);
14701    }
14702
14703    /**
14704     * @api {get} /user/waiting/getRegion getRegion()
14705     * @apiName getRegion
14706     * @apiGroup Waiting
14707     * @apiDescription Retrieves the list of countries and their regions based on the user's language in Native Camp. It returns the country and region details.
14708     *
14709     * @apiSuccess {Boolean} success Indicates whether the request was successful.
14710     * @apiSuccess {Array} regionDetails The list of countries and their regions.
14711     * @apiSuccess {Object} regionDetails.country The details of a country.
14712     * @apiSuccess {String} regionDetails.country.country_name The name of the country.
14713     * @apiSuccess {Array} regionDetails.country.regions The list of regions in the country.
14714     * @apiSuccess {Object} regionDetails.country.regions.region The details of a region.
14715     * @apiSuccess {String} regionDetails.country.regions.region.id The ID of the region.
14716     * @apiSuccess {String} regionDetails.country.regions.region.region_name The name of the region.
14717     *
14718     * @apiSuccessExample {json} Success-Response:
14719     *     {
14720     *         "success": true,
14721     *         "regionDetails": [
14722     *             {
14723     *                 "country_name": "Japan",
14724     *                 "regions": [
14725     *                     {
14726     *                         "id": "1",
14727     *                         "region_name": "Kanto"
14728     *                     },
14729     *                     ...
14730     *                 ]
14731     *             },
14732     *             ...
14733     *         ]
14734     *     }
14735     *
14736     * @apiError {Boolean} success Indicates whether the request was successful.
14737     * @apiError {String} message The error message.
14738     *
14739     * @apiErrorExample {json} Error-Response:
14740     *     {
14741     *         "success": false,
14742     *         "message": "Failed to retrieve region details."
14743     *     }
14744     * 
14745     * @apiSampleRequest off
14746     */
14747    public function getRegion() {
14748        $this->autoRender = false;
14749
14750        $userLang = $this->localizeDir ? $this->localizeDir : Configure::read('original_language_default');
14751        $languageId = Configure::read('english_language_id'); // set default
14752        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
14753
14754        foreach($languageIds as $key => $language) {
14755            if (strtolower($language) == strtolower($userLang)) {
14756                $languageId = $key;
14757                break;
14758            }
14759        }
14760    
14761        $countryRegions = $this->CountryRegion->getCountryResidence([], $languageId, true);
14762        $countryRegionData = array();
14763        
14764        foreach ($countryRegions as $key => $countryRegion) {
14765            $countryRegionData[$countryRegion['CountryCode']['id']]['country_name'] = !empty($countryRegion['GlobalCountryCode']['gl_name']) ? $countryRegion['GlobalCountryCode']['gl_name'] : $countryRegion['CountryCode']['country_name'];
14766            $countryRegionData[$countryRegion['CountryCode']['id']]['regions'][] = [
14767                'id' => $countryRegion['CountryRegion']['id'],
14768                'region_name' => !empty($countryRegion['GlobalCountryRegion']['gl_name']) ? $countryRegion['GlobalCountryRegion']['gl_name'] : $countryRegion['CountryRegion']['region_name']
14769            ];
14770        }
14771
14772        $response = [
14773            'success' => true,
14774            'regionDetails' => array_values($countryRegionData)
14775        ];
14776
14777        return json_encode($response);
14778    }
14779
14780
14781    //get the country and region/city if display flag is on and delete flag is 0 ; 0 = not deleted
14782    function getResidenceData($getCRData) {
14783        $residenceData = [
14784            'countryName' => '',
14785            'countryFlag' => 'other',
14786            'regionName' => ''
14787        ];
14788        if ((empty($getCRData['CountryCode']['country_name']) && empty($getCRData['CountryRegion']['region_name']))) {
14789            return $residenceData;
14790        }
14791        if ($getCRData['CountryCode']['display_flag'] != 1) {
14792            return $residenceData;
14793        }
14794        if (empty($getCRData['TeacherDetail']['country_id'])) {
14795            return $residenceData;
14796        }
14797        if ($getCRData['CountryRegion']['delete_flag'] == 1) {
14798            return $residenceData;
14799        }
14800    
14801        $residenceData['countryName'] = isset($getCRData['GlobalCountryCode']['gl_name']) ? $getCRData['GlobalCountryCode']['gl_name'] : $getCRData['CountryCode']['country_name'];
14802        $getCountryCode = $this->CountryCode->getCountryFromId($getCRData['TeacherDetail']['country_id']);
14803        if ($getCountryCode) {
14804            $countryCodeLower = strtolower($getCountryCode);
14805            $explodeCountryCode = explode(' ', $countryCodeLower);
14806            $residenceData['countryFlag'] = implode('_', $explodeCountryCode);
14807        }
14808    
14809        if (isset($getCRData['GlobalCountryRegion']['gl_name'])) {
14810            $residenceData['regionName'] = $getCRData['GlobalCountryRegion']['gl_name'];
14811        } elseif (isset($getCRData['CountryRegion']['region_name'])) {
14812            $residenceData['regionName'] = $getCRData['CountryRegion']['region_name'];
14813        }
14814
14815        return $residenceData;
14816    }
14817
14818
14819    /**
14820     * @api {post} /user/waiting/countTeacherReservedLessons countTeacherReservedLessons()
14821     * @apiName countTeacherReservedLessons
14822     * @apiGroup Waiting
14823     * @apiDescription Counts the number of reserved lessons for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation count.
14824     *
14825     * @apiBody {String} teacher_id The ID of the teacher.
14826     * 
14827     * @apiSuccess {Number} reservation_count The number of reserved lessons for the teacher.
14828     *
14829     * @apiSuccessExample {json} Success-Response:
14830     *     {
14831     *         "reservation_count": 5
14832     *     }
14833     *
14834     * @apiError {String} error Message indicating the error.
14835     *
14836     * @apiErrorExample {json} Error-Response:
14837     *     {
14838     *         "error": "Invalid request data."
14839     *     }
14840     * 
14841     * @apiSampleRequest off
14842     */
14843    public function countTeacherReservedLessons(){
14844        $this->autoRender = false;
14845        $this->layout = false;
14846        $reserveCount = array('reservation_count' => 0);
14847
14848        if ( $this->request->is('ajax') && !empty($this->request->data['teacher_id']) ) {
14849            $teacherId = $this->request->data['teacher_id'];
14850            $reserveCount['reservation_count'] = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId));
14851        }
14852        return json_encode($reserveCount);
14853    }
14854
14855    /**
14856     * Get Live coupon result for viewers
14857     * @param chathash
14858     * @param users_api_token
14859     * @return json
14860     */
14861    public function getLiveCouponResult()
14862    {
14863        $this->autoRender = false;
14864        $this->layout = false;
14865
14866        $users_api_token = $this->request->data['users_api_token'];
14867        $chat_hash = $this->request->data['chat_hash'];
14868        // open tunnel
14869        myTools::initializeApiTunnel(array('LessonDataController'));
14870
14871        // initialize controller
14872        $lcr = new LessonDataController();
14873
14874        // set data
14875        $lcr->params = [
14876            'nc_terminal_type' => 1,
14877            'chat_hash' => $chat_hash,
14878            'users_api_token' => $users_api_token
14879        ];
14880
14881        // process payment
14882        $response = json_decode($lcr->live_coupon_result(), true);
14883        return json_encode($response);    }
14884
14885    public function checkLessonStartButtonNormal() {
14886        $this->autoRender = false;
14887        $this->layout = false;
14888        $user = $this->sharedUserData;
14889        $data = $this->request->data;
14890        $response = [];
14891        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
14892        $env = Configure::read('ENVIRONMENT');
14893
14894        if(empty($data['teacherId'])) {
14895            $response['error'] = 'Invalid parameters!';
14896            return json_encode($response);
14897        }
14898
14899        $studentId = (int) $data['studentId'];
14900        $teacherId = (int) $data['teacherId'];
14901        $counselingFlg = $data['counselingFlg'] ?? 0;
14902        myTools::initializeApiTunnel(array('TeachersDetailController'));
14903        $TeachersDetailController = new TeachersDetailController();
14904        $TeachersDetailController->params = [
14905            'nc_terminal_type' => 1, // pc
14906            'users_api_token' => $user['User']['api_token'],
14907            'teachers_id' => (int) $data['teacherId'],
14908            'la' => $data['la']
14909        ];    
14910        $api = json_decode($TeachersDetailController->detail(), true);        
14911
14912        if (json_last_error() !== JSON_ERROR_NONE) {
14913            $response['error'] = 'Failed to decode API response.';
14914            return json_encode($response);
14915        }
14916
14917        $isGuestViewer = empty($studentId) ? 1 : 0;
14918        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
14919        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
14920        $lessonStartBtnText10minsRemaining = __d('waiting','レッスン終了まで あと%s分');
14921        $lessonOrangeButtonRemaining = false;
14922        $canLessonParam = array(
14923            'homeFlag' => isset($api['CommonTeacherStatus']['Teacher']['home_flg']) ? $api['CommonTeacherStatus']['Teacher']['home_flg'] : null,
14924            'isGuestViwer' => $isGuestViewer
14925        );    
14926        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);
14927        $liveDefault = (object)[
14928            'max_viewer' => Configure::read('max_live_lesson_viewer'),
14929            'lesson_flg' => 0,
14930            'lesson_joined' => 0,
14931            'lesson_started' => 0,
14932            'lesson_finish' => 0
14933        ];
14934        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;        
14935        
14936        $loginDialog = [
14937            'headerMessage' => __d('login', 'ログインが必要です'),
14938            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
14939            'loginBtn' =>  __d('login', 'ログインはこちら'),
14940            'registerBtn' => __d('login', '新規会員登録はこちら')
14941        ];
14942        $json = [
14943            'lessonStartBtnText' => $lessonStartBtnText,
14944            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
14945            'lessonStartBtnText10minsRemaining' => $lessonStartBtnText10minsRemaining,
14946            'isGuestViewer' => (bool) $isGuestViewer,
14947            'loginDialog' => $loginDialog,
14948            'fullBaseUrl' => $this->baseUrl,
14949            'canLesson' => $canLesson
14950        ];
14951        $remainingLessonTime = 0;
14952        
14953        $canMidwayLesson = false;
14954        $isViewer = 0;
14955        $onair = $api['LessonOnair'];
14956        $hasRemainingLife = false;
14957        $unsupportedBrowser = false;
14958        $browser = $this->request->header('User-Agent');
14959
14960        if (preg_match('/(Edg|Edge)/i',$browser) ) {
14961            $unsupportedBrowser = false;
14962        } elseif (preg_match('/(OPR)/i',$browser)) {
14963            $unsupportedBrowser = true;
14964        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
14965            $unsupportedBrowser = false;
14966        } else {
14967            $unsupportedBrowser = true;
14968        }
14969
14970        $currentMin = date('i');
14971
14972        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
14973            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
14974        } else {
14975            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
14976        }
14977
14978        if(
14979            $liveData->lesson_flg && 
14980            (
14981                (
14982                    !is_null($onair['user_id']) &&
14983                    $onair['user_id'] == $studentId
14984                )
14985                ||
14986                (
14987                    is_null($onair['user_id']) &&
14988                    $reservedId &&
14989                    $reservedId != $studentId
14990                )
14991            )
14992        ) {
14993            $isViewer = 1;
14994        }
14995
14996        if(!$isGuestViewer) {        
14997            if(!empty($api['error'])) {
14998                $json['api_error'] = $api['error'];
14999                return json_encode($json);
15000            }
15001
15002            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15003            $stateButton = $api['teacher']['state_button'];
15004            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15005            $_teacherStatus = $api['TeacherStatus'];
15006            $reservedLessonData = $api['reservedLessonData'];
15007            $isReserved = $api['isReserved'];
15008            $teacher = $api['CommonTeacherStatus']['Teacher'];
15009            $remainingLessonTime = $api['remainingLessonTime'];
15010            $checkBadge = $api['checkBadge'];
15011            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15012            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15013            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15014            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15015            $userNotEligible = false;
15016            $lessonType = false;
15017            $lessonOnOther = false;
15018            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
15019            $userDuplicateLesson = false;
15020            $isReservedCanSuddenLesson = false;
15021            $isReservedCanLessonViewing = false;
15022            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
15023            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
15024            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
15025            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
15026            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
15027            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
15028            $hasLessonBeforeActualTime = false;
15029            $teacherStatusColor = '';
15030            $ownReservationFlg = 0;
15031            $liveStatus = 0;
15032            $isBusy = false;
15033            $use7DaysTrialModal = false;
15034            $redirectPlanUrl = '';
15035            $teacherLeaveNotice = '';
15036            $showNativeSpeakerWarning = false;
15037            $baseUrl = myTools::getUrl($this->localizeDir);
15038
15039            // get reservation
15040            $nextReservation = LessonScheduleTable::getReservation(array(
15041                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
15042                'LessonSchedule.user_id' => $data['studentId']
15043            ));
15044
15045            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
15046            $queryCondition = array(
15047                'fields' => array(
15048                    'TeacherRankCoin.coins',
15049                    'TeacherRankCoin.reserve_coin_settings_flg',
15050                    'LessonOnair.id',
15051                    'LessonOnair.teacher_id',
15052                    'LessonOnair.user_id',
15053                    'TeacherRankCoin.limited_plan_reservation'
15054                ),
15055                'joins' => array(
15056                    array(
15057                        'type' => 'LEFT',
15058                        'table' => 'teacher_rank_coins',
15059                        'alias' => 'TeacherRankCoin',
15060                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
15061                    )
15062                ),
15063                'conditions' => array(
15064                    array('Teacher.id' => $teacher['id'])
15065                ),
15066                'show' => 'first'
15067            );
15068
15069            $commonTeacherStatusParams = array(
15070                'page_display' => 'listTeacher',
15071                'query_conditions' => $queryCondition
15072            );
15073
15074            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15075            $loStatusParams = array(
15076                'LessonOnair' => $commonTeacher2['LessonOnair'],
15077                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
15078                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
15079                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
15080                'userId' => $studentId
15081            );
15082            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
15083            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
15084            $sapuriCoin = $api['teacher']['sapuri_coin'];
15085
15086            if(empty($reservedLessonData)) {
15087                $this->LessonSchedule->recursive = 0;
15088                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
15089            }
15090
15091            // additional state button check from callLessonAlertandStartButton
15092            if(in_array($stateButton, $stateButtonAddntlCheck)) {
15093                // check if lessonOnair is empty
15094                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
15095                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
15096                    if (!$tmp->id) {
15097                        $api['CommonTeacherStatus']['LessonOnair'] = null;
15098                    }
15099                }
15100                
15101                // check if lessonOnair contains empty values
15102                $oOnair = !empty($teacherStatus1) && empty($onair) 
15103                            ? new TeacherStatusTable($teacherStatus1) 
15104                            : $onair;    
15105
15106                //get next available schedule
15107                $checkNextSchedule = null;
15108                $checkScheduleCurrent = null;
15109                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
15110
15111                if(isset($canLesson['nextReserve'])) {
15112                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
15113                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
15114                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
15115                }
15116
15117                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
15118                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
15119                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
15120
15121                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
15122                if (
15123                    (($canLesson['lessonAvailable']
15124                    && !$checkNextSchedule 
15125                    && $checkScheduleCurrent)
15126                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
15127                    && !($api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1)
15128                    && !$isEmergencyLesson  # ~don't show in emergency page
15129                    && !$this->isStudySapuriTosUser
15130                    && $api['CommonTeacherStatus']['Teacher']['home_flg'] != 1 // not home based teacher
15131                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
15132                ) {
15133                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
15134                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
15135                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
15136                }
15137
15138                // NJ-29831: check if user has reserved lesson for the next 5 min
15139                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherId);
15140                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
15141                $hasLessonBeforeActualTime = false;
15142
15143                if (!empty($scheduleReservationData) && !$onGoingLesson) {
15144                    $hasLessonBeforeActualTime = true;
15145                    $isReserved = true;
15146                }
15147    
15148                //get preset textbook or last viewed
15149                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
15150    
15151                //add additional parameter in fetching preset textbook
15152                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
15153                    $presetParams["lang"] = $this->localizeDir;
15154                }
15155    
15156                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
15157                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
15158                    # for preset
15159                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
15160                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15161    
15162                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
15163                    # use last viewed textbook if no preset data.
15164                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
15165                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15166                }
15167    
15168                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
15169                $presetParams['is_pc_flg'] = 1;
15170    
15171                # fetch preset
15172                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15173                if(!$preset) {
15174                    unset($presetParams['connect_id']);
15175                    unset($presetParams['last_opened_date']);
15176                    $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15177                }
15178    
15179                $lessonData = $preset["textbook_info"];
15180                $categoryId = $lessonData["TextbookCategory"]["id"];
15181                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
15182                $textbookId = $lessonData["Textbook"]["id"];
15183                
15184                if( $categoryTypeId == 1 ) { // course
15185                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
15186                } else { // series
15187                    $seriesId = $categoryId;
15188                }
15189
15190                if(empty($checkBadge)) {
15191                    $checkBadge = $this->TeacherBadge->find("first", array(
15192                        "conditions" => array(
15193                            "TeacherBadge.teacher_id" => $teacherId,
15194                            "TeacherBadge.textbook_category_id" => $seriesId
15195                        ),
15196                        "fields" => array("TeacherBadge.id"),
15197                        "recursive" => -1
15198                    ));
15199                }
15200
15201                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
15202
15203                //check if the preset textbook is doesn't have reserve_flg
15204                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
15205                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
15206                $browser =  $this->request->header('User-Agent');
15207                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15208
15209                if ($uOnair != null) {
15210                    $uOOnair = new LessonOnairTable($uOnair);
15211                    //check user duplicate lesson
15212                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
15213                        $userDuplicateLesson = true;
15214                        $lessonType = $uOOnair->lesson_type;
15215                    }
15216                    //check lesson on others
15217                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
15218                        $lessonOnOther = true;
15219                    }
15220                }
15221
15222                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
15223                if (
15224                    $canLessonTextbook &&             # - can lesson with the textbook
15225                    !$textbookForReservationOnly && # - textbook not for reserve only
15226                    !$unsupportedBrowser &&         # - supported browser
15227                    $userDuplicateLesson &&         # - has lesson with other teacher
15228                    $lessonType == Configure::read('lesson.type.reservation') &&
15229                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15230                    !$this->isStudySapuriUser &&    # - not sapuri user
15231                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
15232                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15233                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15234                ) {
15235                    $isReservedCanSuddenLesson = true;
15236                }
15237
15238                // if failed settlement -> paid or corporate individual (standard/premium)
15239                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
15240                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
15241                // if free 
15242                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
15243                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
15244                // if free (trial not yet conducted)
15245                } elseif ($this->userMembershipType == 13) {
15246                    $userNotEligible = 10;
15247                    $use7DaysTrialModal = true;
15248                // if corporate company settlement failed -> standard/premium or
15249                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
15250                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
15251                }
15252
15253                if( $teacherStatusNew == '5' ) {
15254                    $ownReservationFlg = 1;
15255                }
15256
15257                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
15258                $membershipTypeReservationOnly = false;
15259
15260                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
15261                    $membershipTypeReservationOnly = true;
15262                }
15263
15264                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
15265                $membershipTypeBlueBtn = false;
15266
15267                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
15268                    $teacherStatusColor = 'wait';
15269                    $membershipTypeBlueBtn = true;
15270                }
15271
15272                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
15273
15274                if(!$isGuestViewer && $liveLessonFlg) {
15275                    $reservedLessonData = $api['reservedLessonData'];
15276
15277                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
15278                        $liveStatus = 0;
15279                    } else {
15280                        //- if lesson started
15281                        if (
15282                            !is_null($api['LessonOnair']['connect_id']) &&
15283                            !is_null($api['LessonOnair']['user_id'])
15284                        ) {
15285                            if ($api['LessonOnair']['user_id'] == $studentId) {
15286                                $liveStatus = 4;
15287                            } else {
15288                                //- check live status
15289                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
15290                                    'user_id' => $studentId,
15291                                    'chat_hash' => $api['LessonOnair']['chat_hash']
15292                                ]);
15293
15294                                //-- override status to watch
15295                                if ($liveStatus == 1) {
15296                                    $liveStatus = 2; //view live
15297                                }
15298                            }
15299                        } else {
15300                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
15301                                'teacher_id' => $teacherId
15302                            ]);
15303
15304                            //-has reservation
15305                            if ($waitingReservationLive) {
15306                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
15307                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
15308                                } else {
15309                                    $liveStatus = 1; //live will start
15310                                }
15311                            }
15312                        }
15313                    }
15314                }
15315
15316                if(!$this->isStudySapuriTosUser) {
15317                    $teacherStudentConnection = $api['teacherStudentConnection'];        
15318                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
15319                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
15320                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
15321                            'teacher_id' => $teacherId,
15322                            'teacherStudentData' => $teacherStudentData,
15323                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
15324                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
15325                            'nickname' => $user['User']['nickname'],
15326                            'admin_flg' => $userAdminFlag,
15327                            'isReserved' => $isReserved,
15328                            'type' => 1
15329                        ));
15330                    }
15331                }
15332
15333                // check if busy
15334                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
15335                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
15336                        $isBusy = true;
15337                    }
15338                }
15339
15340                if(!$isGuestViewer && !isset($remainingLessonTime) || $remainingLessonTime <= 0 || $remainingLessonTime >= 660) {
15341                    $isBusy = true;
15342                }
15343
15344                // NC-5409 : Corporate Limited Plan
15345                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
15346
15347                    // check if legible
15348                    if (
15349                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
15350                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15351                            $userDuplicateLesson || 
15352                            $unsupportedBrowser ||
15353                            $lessonOnOther
15354                        ) &&
15355                        $studentId
15356                    ) {
15357                        $userNotEligible = 1;
15358                    }
15359
15360                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
15361
15362                    $corpLightCondition1 = (
15363                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
15364                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15365                        $userDuplicateLesson ||
15366                        $unsupportedBrowser ||
15367                        $lessonOnOther
15368                    );
15369                    // check if legible
15370                    if ( $corpLightCondition1 && $studentId) {
15371                        $userNotEligible = 2;
15372                    }
15373                } elseif (
15374                    (
15375                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
15376                        $commonTeacher2['Teacher']['native_speaker_flg']
15377                    ) &&
15378                    (
15379                        $user['User']['native_option'] == null ||
15380                        $user['User']['native_option'] == 0
15381                    ) &&
15382                    !$isReserved &&
15383                    !$tmp->live_lesson_flg &&
15384                    !$this->isStudySapuriTosUser
15385                ) {
15386                    $userNotEligible = 3;
15387                    $showNativeSpeakerWarning = true;
15388                } elseif ( // NJ-48797
15389                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
15390                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
15391                    !$isReserved &&
15392                    !$tmp->live_lesson_flg &&
15393                    !$this->isStudySapuriTosUser
15394                ) {
15395                    $showNativeSpeakerWarning = true;
15396                    $userNotEligible = 4;
15397                } else {
15398                    // check if legible
15399                    if ((
15400                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
15401                        $userDuplicateLesson || 
15402                        $unsupportedBrowser || 
15403                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
15404                        $lessonOnOther
15405                    ) && $studentId) {
15406                        $userNotEligible = 5;
15407                    }
15408                }
15409
15410                # ~no sudden lesson for sapuri toS user
15411                if ($this->isStudySapuriTosUser && !$isReserved) {
15412                    $userNotEligible = 6;
15413                }
15414
15415                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
15416
15417                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
15418                    # disable the lesson button for lite plan if it is not reserved lesson
15419                    $userNotEligible = 7;
15420
15421                    # add if reserve is still ongoing 
15422                    if($isReserved) {
15423                        $userNotEligible = false;
15424                    }
15425                }
15426
15427            }            
15428
15429            switch($stateButton) {
15430                case 2: //proceed_to_the_lesson_immediately
15431                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
15432                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
15433                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
15434                    ) {
15435                        $stateButton = 5; //busy
15436                    }
15437                    break;
15438                case 3: // go to reserved lesson
15439                case 32: // dummy lesson
15440                    $teacherStatusColor = 'lesson';
15441                case 5: //busy
15442                    if( $teacherStatusColor == 'offline' && $membershipTypeReservationOnly ) {
15443                        $stateButton = 6;
15444                    }
15445                    $teacherStatusColor = 'lesson';
15446
15447                    break;
15448                default:
15449            }
15450
15451            $studentRemainingSecondsDelay = 0;
15452            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
15453
15454            $showTakeBusinessTestModal = false;
15455            if (isset($user['User']['corporate_id'])) {
15456                $showTakeBusinessTestModal = false;
15457                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
15458                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
15459                $corporateUserDate = time();
15460                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
15461
15462                if (
15463                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
15464                    !$isReserved &&
15465                    (
15466                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
15467                        (
15468                            $userAdminFlag == 1 ||
15469                            (
15470                                isset($user["User"]["nickname"]) &&
15471                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
15472                            )
15473                        )
15474                    )
15475                ) {
15476                    $showTakeBusinessTestModal = true;
15477                }
15478            }
15479
15480            // show orange button
15481            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($studentId, $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
15482
15483            if (
15484                $canLessonTextbook &&             # - can lesson with the textbook
15485                !$textbookForReservationOnly && # - textbook not for reserve only
15486                !$unsupportedBrowser &&         # - supported browser
15487                $userDuplicateLesson &&         # - has lesson with other teacher
15488                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15489                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15490                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15491            ) {
15492                $canMidwayLesson = true;
15493            }
15494        } else {
15495
15496        } //end $isGuestViewer
15497
15498        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
15499        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
15500        $showLoader = $isGuestViewer ? true : false;    
15501        $suddenLessonFlg = false;
15502        $canDoLive = UserTable::canJoinLiveViewing($user['User']);        
15503
15504        if (
15505            $isReserved && 
15506            (
15507                $this->isStudySapuriUser || 
15508                $this->isStudySapuriTosUser || 
15509                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
15510            )
15511        ) {
15512            $canDoLive = false;
15513        }
15514    
15515        if(
15516            !$isViewer && 
15517            !$isEmergencyLesson && 
15518            !$isReservedCanSuddenLesson & 
15519            !$canMidwayLesson &&
15520            !$isReserved
15521        ) {
15522            if($teacherStatusColor == 'wait') {
15523                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
15524                    $isBusy = true;
15525                }
15526    
15527                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
15528                    $suddenLessonFlg = true;
15529                }
15530            }
15531    
15532            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
15533                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
15534                    
15535                    if($membershipTypeBlueBtn) {
15536                        $suddenLessonFlg = true;
15537                        $teacherStatusColor = 'wait';
15538                    }
15539                }
15540            }
15541        }
15542
15543        // set localize url
15544        if (
15545            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
15546            $get['la'] != Configure::read('default.user_language')
15547        ) {
15548            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
15549        } else {
15550            $localizeUrl = myTools::getUrl();
15551        }
15552
15553        $displayFamilyAlert = false;
15554        if (
15555            isset($this->sharedUserData['User']['parent_id']) &&
15556            !is_null($this->sharedUserData['User']['parent_id'])
15557        ) {
15558            $parent = $this->User->find('first', array(
15559                'fields' => array(
15560                    'User.id',
15561                    'User.hash16',
15562                    'User.charge_flg'
15563                ),
15564                'conditions' => array(
15565                    'User.id' => $this->sharedUserData['User']['parent_id']
15566                ),
15567                'recursive' => -1
15568            ));
15569
15570            if ($parent && $parent['User']['charge_flg'] != 1) {
15571                $displayFamilyAlert = true;
15572            }
15573        }
15574
15575        $device = false;
15576        if (strpos($ua, 'Silk') !== false) {
15577            $device = 'kindle';
15578        } else if (strpos($ua, 'Android') !== false) {
15579            $device = 'andriod';
15580        } else if (strpos($ua, 'iPhone') !== false) {
15581            $device = 'ios';
15582        } else if (strpos($ua, 'iPad') !== false) {
15583            $device = 'ios';
15584        } else if (strpos($ua, 'iPod') !== false) {
15585            $device = 'ios';
15586        } else {
15587            $device = 'pc';
15588        }
15589
15590        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
15591        $button = $buttonStates[$stateButton];
15592        $canEmergencyLesson = false;
15593        $currentMinutes = date("i");
15594        $emergencyBreakTime = ['status' => false];
15595        $currentHour = date("H");
15596        
15597        if ($isEmergencyLesson) {
15598            if ($this->isStudySapuriTosUser) {
15599                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
15600                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
15601                $queryCondition['fields'][] = "(
15602                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
15603                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
15604                    ) as can_emergency_lesson";
15605                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
15606                    as student_no_next_reservation";
15607            }
15608
15609            $commonTeacherStatusParams = array(
15610                'page_display' => 'listTeacher',
15611                'query_conditions' => $queryCondition
15612            );
15613            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15614            
15615            if (
15616                $this->isStudySapuriTosUser &&
15617                !$isReserved &&
15618                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
15619                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
15620                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
15621                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
15622            ) {
15623                $canEmergencyLesson = true;
15624            }
15625
15626            # ~if emergency lesson break time
15627            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
15628                $canEmergencyLesson = false;
15629                $emergencyBreakTime['status'] = true;
15630                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
15631                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
15632            }
15633        }        
15634
15635
15636        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
15637
15638        // lesson alert
15639        $lessonAlertMsg = [];
15640        $lessonAlertStatus = '';
15641
15642        // if emergency lesson break time
15643        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
15644            $lessonAlertMsg = [
15645                ['text' => __d('waiting','しばらくお待ちください。')],
15646                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
15647                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
15648            ];
15649            $lessonAlertStatus = 'emergency_lesson_break_time';
15650        }
15651
15652        if (
15653            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
15654            !$isReserved &&
15655            !$isAvatar
15656        ) {
15657            $lessonAlertMsg = [
15658                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
15659                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
15660                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
15661            ];
15662            $lessonAlertStatus = 'exceed_daily_limit';
15663        }
15664
15665        $schedStartTime = isset($canLesson['nextReservation']['lesson_time']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReservation']['lesson_time']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15666        $schedEndTime = isset($canLesson['possibleTime']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['possibleTime']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15667
15668        if(
15669            isset($canLesson['possibleTime']) &&
15670            $canLesson['possibleTime'] !== false &&
15671            (!isset($isAvatar) || $isAvatar == false) &&
15672            $studentId &&
15673            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15674            !$isEmergencyLesson
15675        ) {
15676            $canReserveLessonForReserved = 1;
15677        } else {
15678            $canReserveLessonForReserved = 0;
15679        }
15680
15681        if(
15682            isset($canLesson['possibleTime']) &&
15683            $canLesson['possibleTime'] !== false &&
15684            $isAvatar == false &&
15685            $studentId &&
15686            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15687            !$this->isStudySapuriTosUser && !$isEmergencyLesson # ~don't show in emergency page
15688        ) {
15689            $lessonAlertStatus == 'lesson_reservation';
15690            $lessonAlertMsg = ['text' => sprintf(__d('waiting','この講師は、%1$s から予約が入っているため、%2$s までのレッスンとなります。ご了承の上レッスンへお進みください。'), $schedStartTime, $schedEndTime)];
15691        }
15692
15693        // user has reserved class (attempts to have a lesson with another teacher)
15694        if (
15695            $isAvatar == false && 
15696            $reservedLessonData && 
15697            (!$canLesson['lessonAvailable']) && !empty($teacherStatus) && ($teacherStatus->status == 1) && 
15698            (!empty($teacherStatus) && isset($teacherStatus->connect_flg) && $teacherStatus->connect_flg == 1 ) && 
15699            !$isReservedCanSuddenLesson
15700        ) {
15701            $lessonAlertStatus = 'reserved_class';
15702        }
15703
15704        $corporateIndividualUser = false;
15705        $corporateTypes = Configure::read('corporate_type_arr');
15706        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15707        if (isset($user['User']['corporate_id'])) {
15708            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
15709            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
15710        }
15711
15712        if (
15713            !$this->isStudySapuriUser &&
15714            $lessonType == Configure::read('lesson.type.reservation') &&
15715            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
15716        ) {
15717            $isReservedCanLessonViewing = true;
15718        }
15719
15720        if(!$isGuestViewer) {
15721            $json = array_merge($json, [
15722                'apiStateButton' => $api['teacher']['state_button'],
15723                'button' => $button,
15724                'canDoLive' => $canDoLive,
15725                'canEmergencyLesson' => $canEmergencyLesson,
15726                'canLesson' => $canLesson,
15727                'canLessonTextbook' => $canLessonTextbook,
15728                'canMidwayLesson' => $canMidwayLesson,
15729                'canReserveLessonForReserved' => $canReserveLessonForReserved,
15730                'checkBadge' => $checkBadge,
15731                'corporateIndividualUser' => $corporateIndividualUser,
15732                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
15733                'corporateType' => $corporateType,
15734                'corporateUserFlg' => $corporateUserFlg,
15735                'corpLightCondition' => $corpLightCondition1,
15736                'counselingFlg' => $counselingFlg,
15737                'device' => $device,
15738                'displayFamilyAlert' => $displayFamilyAlert,
15739                'dummyLessonRoom' => $hasLessonBeforeActualTime,
15740                'emergencyBreakTime' => $emergencyBreakTime,
15741                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
15742                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
15743                'hasRemainingLife' => $hasRemainingLife,
15744                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
15745                'isAvatar' => $isAvatar,
15746                'isBusy' => $isBusy,
15747                'isEmergencyLesson' => $isEmergencyLesson,
15748                'isNormalLitePlanUser' => $isNormalLitePlanUser,
15749                'isRedLamp' => $isRedLamp,
15750                'isReserved' => $isReserved,
15751                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
15752                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
15753                'isStudySapuriTosUser' => $this->isStudySapuriUser,
15754                'isViewer' => $isViewer,
15755                'lessonAlertMsg' => $lessonAlertMsg,
15756                'lessonAlertStatus' => $lessonAlertStatus,
15757                'lessonOnAir' => $teacherStatusOnAir,
15758                'lessonOnOther' => $lessonOnOther,
15759                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
15760                'lessonType' => $lessonType,
15761                'liveData' => $liveData,
15762                'liveLessonFlg' => $liveLessonFlg ?? null,
15763                'liveLessonText' => $liveLessonText,
15764                'liveStatus' => $liveStatus,
15765                'localizeUrl' => $localizeUrl,
15766                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
15767                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
15768                'onair' => $onair,
15769                'uOnair' => $uOnair,
15770                'onGoingLesson' => $onGoingLesson,
15771                'ownReservationFlg' => $ownReservationFlg,
15772                'paymentPlanId' => $user['User']['payment_plan_id'],
15773                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
15774                'redirectPlanUrl' => $redirectPlanUrl,
15775                'remainingLessonTime' => (int) $remainingLessonTime,
15776                'reservedLessonData' => $reservedLessonData,
15777                'sapuriCoin' => $sapuriCoin,
15778                'scheduleReservationData' => $scheduleReservationData,
15779                'schedEndTime' => $schedEndTime,
15780                'schedStartTime' => $schedStartTime,
15781                'showLoader' => $showLoader,
15782                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
15783                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
15784                'stateButton' => $stateButton,
15785                'studentId' => $studentId,
15786                'suddenLessonFlg' => $suddenLessonFlg,
15787                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
15788                'teacherLeaveNotice' => $teacherLeaveNotice,
15789                'teacherStatus' => $teacherStatus,
15790                'teacherStatusApi' => $_teacherStatus,
15791                'teacherStatusColor' => $teacherStatusColor,
15792                'textbookForReservationOnly' => (int)$textbookForReservationOnly,
15793                'unverifiedSMS' => $stateButton == 7 ? true : false,
15794                'unsupportedBrowser' => $unsupportedBrowser,
15795                'use7DaysTrialModal' => $use7DaysTrialModal,
15796                'userAdminFlag' => $userAdminFlag,
15797                'userDoubleCheckFlag' => $userDoubleCheckFlag,
15798                'userDuplicateLesson' => $userDuplicateLesson,
15799                'userFailFlag' => $userFailFlag,
15800                'userMembershipType' => $this->userMembershipType,
15801                'userNativeOption' => $user['User']['native_option'],
15802                'userNotEligible' => $userNotEligible
15803            ]);
15804
15805            if($membershipTypeReservationOnly) {
15806                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
15807            }
15808
15809            if(
15810                $remainingLessonTime > 0 && 
15811                $remainingLessonTime < 660 &&
15812                !empty($teacherStatusOnAir['user_id']) && $teacherStatusOnAir['user_id'] != $studentId
15813            ) {
15814                $json['remainingLessonEndTime'] = $oOnair['end_time'];
15815
15816                if($remainingLessonTime <= 60) {
15817                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで もうすぐ');
15818                } else {
15819                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで あと%s分');
15820                }
15821            }
15822
15823            if($suddenLessonFlg) {
15824                if($use7DaysTrialModal) {
15825                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
15826                } else if (!empty(trim($redirectPlanUrl))) {
15827                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
15828                } else if ($showNativeSpeakerWarning) {
15829                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
15830                } else if ($unsupportedBrowser) {
15831                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
15832                } else if (!$canLessonTextbook) {
15833                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
15834                } else if (!empty($teacherLeaveNotice)) {
15835                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
15836                }
15837
15838                if(!empty($json['suddenLessonStatus'])) {
15839                    $json['validateSuddenLessonFlg'] = false;
15840                } else {
15841                    $json['validateSuddenLessonFlg'] = true;
15842                }
15843            }
15844
15845        } else if ($isGuestViewer || $isViewer) {
15846            $json = array_merge($json, [
15847                'canLesson' => $canLesson,
15848                'isViewer' => $isViewer,
15849            ]);
15850        }
15851
15852        if($env != 'PRODUCTION') {
15853            $json['api'] = $api;
15854            $json['commonTeacher2'] = $commonTeacher2;
15855            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
15856            $json['teacherStudentConnection'] = $api['teacherStudentConnection'];
15857            $json['tmpLessonOnAir'] = $tmp;
15858            $json['nextEmergencySlot'] = $nextEmergencySlot;
15859            $json['nextReserveSlot'] = $nextReserveSlot;
15860        }
15861
15862        return json_encode($json);
15863    }
15864
15865    public function checkLessonStartButtonAvatar() {
15866        $this->autoRender = false;
15867        $this->layout = false;
15868        $user = $this->sharedUserData;
15869        $data = $this->request->data;
15870        $response = [];
15871        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
15872        $env = Configure::read('ENVIRONMENT');
15873    
15874        if(empty($data['teacherId'])) {
15875            $response['error'] = 'Invalid parameters!';
15876            return json_encode($response);
15877        }
15878    
15879        // if api token is not set
15880        if (empty($user['User']['api_token'])) {
15881            $userApiToken = $this->User->generateAndSaveApiToken($data['studentId']);
15882            $this->Session->write('Auth.User.api_token', $userApiToken);
15883        }
15884    
15885        $studentId = (int) $data['studentId'];
15886        $teacherId = (int) $data['teacherId'];
15887        $counselingFlg = $data['counselingFlg'] ?? 0;
15888        myTools::initializeApiTunnel(array('TeachersDetailController'));
15889        $TeachersDetailController = new TeachersDetailController();
15890        $TeachersDetailController->params = [
15891            'nc_terminal_type' => 1, // pc
15892            'users_api_token' => $user['User']['api_token'],
15893            'teachers_id' => (int) $data['teacherId'],
15894            'la' => $data['la']
15895        ];    
15896        $api = json_decode($TeachersDetailController->detail(), true);
15897
15898        if (json_last_error() !== JSON_ERROR_NONE) {
15899            $response['error'] = 'Failed to decode API response.';
15900            return json_encode($response);
15901        }
15902
15903        $isGuestViewer = empty($studentId) ? 1 : 0;
15904        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
15905        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
15906        $lessonOrangeButtonRemaining = false;
15907        $loginDialog = [
15908            'headerMessage' => __d('login', 'ログインが必要です'),
15909            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
15910            'loginBtn' =>  __d('login', 'ログインはこちら'),
15911            'registerBtn' => __d('login', '新規会員登録はこちら')
15912        ];
15913        $json = [
15914            'lessonStartBtnText' => $lessonStartBtnText,
15915            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
15916            'isGuestViewer' => (bool) $isGuestViewer,
15917            'loginDialog' => $loginDialog,
15918            'fullBaseUrl' => $this->baseUrl,
15919        ];
15920        $canLessonParam = array(
15921            'homeFlag' => isset($api['teacher']['home_flg']) ? $api['teacher']['home_flg'] : null,
15922            'isGuestViwer' => $isGuestViewer
15923        );
15924        $canMidwayLesson = false;
15925        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);    
15926        $liveDefault = (object)[
15927            'max_viewer' => Configure::read('max_live_lesson_viewer'),
15928            'lesson_flg' => 0,
15929            'lesson_joined' => 0,
15930            'lesson_started' => 0,
15931            'lesson_finish' => 0
15932        ];
15933        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;
15934        $currentMin = date('i');
15935        $isViewer = 0;
15936        $onair = $api['LessonOnair'];
15937        $hasRemainingLife = false;
15938        $unsupportedBrowser = false;
15939        $browser =  $this->request->header('User-Agent');
15940
15941        if (preg_match('/(Edg|Edge)/i',$browser) ) {
15942            $unsupportedBrowser = false;
15943        } elseif (preg_match('/(OPR)/i',$browser)) {
15944            $unsupportedBrowser = true;
15945        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
15946            $unsupportedBrowser = false;
15947        } else {
15948            $unsupportedBrowser = true;
15949        }
15950
15951        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
15952            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
15953        } else {
15954            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
15955        }
15956
15957        if(
15958            $liveData->lesson_flg && 
15959            (
15960                (
15961                    !is_null($onair['user_id']) &&
15962                    $onair['user_id'] == $studentId
15963                )
15964                ||
15965                (
15966                    is_null($onair['user_id']) &&
15967                    $reservedId &&
15968                    $reservedId != $studentId
15969                )
15970            )
15971        ) {
15972            $isViewer = 1;
15973        }
15974
15975        $isGuestViewer = (empty($studentId) && $isViewer) ? 1 : 0;
15976    
15977        if(!$isGuestViewer) {
15978            if(!empty($api['error'])) {
15979                $json['api_error'] = $api['error'];
15980                return json_encode($json);
15981            }
15982    
15983            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15984            $stateButton = $api['teacher']['state_button'];
15985            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15986            $_teacherStatus = $api['TeacherStatus'];
15987            $reservedLessonData = $api['reservedLessonData'];
15988            $isReserved = $api['isReserved'];
15989            $teacher = $api['CommonTeacher`Status']['Teacher'];
15990            $checkBadge = $api['checkBadge'];
15991            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15992            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15993            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15994            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15995            $userNotEligible = false;
15996            $lessonType = false;
15997            $lessonOnOther = false;
15998            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
15999            $userDuplicateLesson = false;
16000            $isReservedCanSuddenLesson = false;
16001            $isReservedCanLessonViewing = false;
16002            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
16003            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
16004            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
16005            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
16006            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
16007            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
16008            $hasLessonBeforeActualTime = false;
16009            $teacherStatusColor = '';
16010            $ownReservationFlg = 0;
16011            $liveStatus = 0;
16012            $isBusy = false;
16013            $use7DaysTrialModal = false;
16014            $redirectPlanUrl = '';
16015            $teacherLeaveNotice = '';
16016            $showNativeSpeakerWarning = false;
16017            $baseUrl = myTools::getUrl($this->localizeDir);                
16018            
16019            // get reservation
16020            $nextReservation = LessonScheduleTable::getReservation(array(
16021                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
16022                'LessonSchedule.user_id' => $data['studentId']
16023            ));
16024
16025            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
16026            $queryCondition = array(
16027                'fields' => array(
16028                        'TeacherRankCoin.coins',
16029                        'TeacherRankCoin.reserve_coin_settings_flg',
16030                        'LessonOnair.id',
16031                        'LessonOnair.teacher_id',
16032                        'LessonOnair.user_id',
16033                        'TeacherRankCoin.limited_plan_reservation'
16034                    ),
16035                'joins' => array(
16036                    array(
16037                        'type' => 'LEFT',
16038                        'table' => 'teacher_rank_coins',
16039                        'alias' => 'TeacherRankCoin',
16040                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
16041                    )
16042                ),
16043                'conditions' => array(
16044                    array('Teacher.id' => $teacherId)
16045                ),
16046                'show' => 'first'
16047            );
16048
16049            $commonTeacherStatusParams = array(
16050                'page_display' => 'listTeacher',
16051                'query_conditions' => $queryCondition
16052            );
16053
16054            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16055            $loStatusParams = array(
16056                'LessonOnair' => $commonTeacher2['LessonOnair'],
16057                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
16058                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
16059                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
16060                'userId' => $studentId
16061            );
16062            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
16063            $teacherParams = array(
16064                    'type' => 'first',
16065                    'args' => array(
16066                        'conditions' => array(
16067                            'id' => $teacherId
16068                        ),
16069                        'recursive' => -1
16070                    )
16071                );
16072            $teacherInfo = $this->Teacher->getTeachers($teacherParams);
16073
16074            if (
16075                ($teacher['avatar_id'] &&
16076                $teacherStatus['status'] == 4)
16077            ) {
16078                $teacherStatusNew = 3;
16079            }
16080
16081            if(empty($reservedLessonData)) {
16082                $this->LessonSchedule->recursive = 0;
16083                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
16084            }
16085
16086            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
16087            $sapuriCoin = $api['teacher']['sapuri_coin'];
16088    
16089            // additional state button check from callLessonAlertandStartButton
16090            if(in_array($stateButton, $stateButtonAddntlCheck)) {
16091                // check if lessonOnair is empty
16092                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
16093                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
16094                    if (!$tmp->id) {
16095                        $api['CommonTeacherStatus']['LessonOnair'] = null;
16096                    }
16097                }
16098    
16099                // check if lessonOnair contains empty values
16100                $oOnair = !empty($teacherStatus1) && empty($onair) 
16101                            ? new TeacherStatusTable($teacherStatus1)
16102                            : $onair;
16103    
16104                //get next available schedule
16105                $checkNextSchedule = null;
16106                $checkScheduleCurrent = null;
16107                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
16108    
16109                if(isset($canLesson['nextReserve'])) {
16110                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
16111                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
16112                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
16113                }
16114    
16115                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
16116                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
16117                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
16118    
16119                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
16120                if (
16121                    (($canLesson['lessonAvailable']
16122                    && !$checkNextSchedule 
16123                    && $checkScheduleCurrent)
16124                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
16125                    && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
16126                    && !$isEmergencyLesson  # ~don't show in emergency page
16127                    && !$this->isStudySapuriTosUser
16128                    && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
16129                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
16130                ) {
16131                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
16132                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
16133                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
16134                }
16135    
16136                // NJ-29831: check if user has reserved lesson for the next 5 min
16137                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
16138                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
16139                $hasLessonBeforeActualTime = false;
16140    
16141                if (!empty($scheduleReservationData) && !$onGoingLesson) {
16142                    $hasLessonBeforeActualTime = true;
16143                    $isReserved = true;
16144                }
16145    
16146                //get preset textbook or last viewed
16147                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
16148    
16149                //add additional parameter in fetching preset textbook
16150                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
16151                    $presetParams["lang"] = $this->localizeDir;
16152                }
16153    
16154                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
16155                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
16156                    # for preset
16157                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
16158                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16159    
16160                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
16161                    # use last viewed textbook if no preset data.
16162                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
16163                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16164                }
16165    
16166                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
16167                $presetParams['is_pc_flg'] = 1;
16168    
16169                # fetch preset
16170                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16171                if(!$preset) {
16172                    unset($presetParams['connect_id']);
16173                    unset($presetParams['last_opened_date']);
16174                    $preset = $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16175                }
16176    
16177                $lessonData = $preset["textbook_info"];
16178                $categoryId = $lessonData["TextbookCategory"]["id"];
16179                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
16180                $textbookId = $lessonData["Textbook"]["id"];
16181                
16182                if( $categoryTypeId == 1 ) { // course
16183                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
16184                } else { // series
16185                    $seriesId = $categoryId;
16186                }
16187
16188                if(empty($checkBadge)) {
16189                    $checkBadge = $this->TeacherBadge->find("first", array(
16190                        "conditions" => array(
16191                            "TeacherBadge.teacher_id" => $teacherId,
16192                            "TeacherBadge.textbook_category_id" => $seriesId
16193                        ),
16194                        "fields" => array("TeacherBadge.id"),
16195                        "recursive" => -1
16196                    ));
16197                }
16198    
16199                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
16200    
16201                //check if the preset textbook is doesn't have reserve_flg
16202                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
16203                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
16204                
16205                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16206    
16207                if ($uOnair != null) {
16208                    $uOOnair = new LessonOnairTable($uOnair);
16209                    //check user duplicate lesson
16210                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
16211                        $userDuplicateLesson = true;
16212                        $lessonType = $uOOnair->lesson_type;
16213                    }
16214                    //check lesson on others
16215                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
16216                        $lessonOnOther = true;
16217                    }
16218                }
16219    
16220                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
16221                if (
16222                    $canLessonTextbook &&             # - can lesson with the textbook
16223                    !$textbookForReservationOnly && # - textbook not for reserve only
16224                    !$unsupportedBrowser &&         # - supported browser
16225                    $userDuplicateLesson &&         # - has lesson with other teacher
16226                    $lessonType == Configure::read('lesson.type.reservation') &&
16227                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16228                    !$this->isStudySapuriUser &&    # - not sapuri user
16229                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
16230                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16231                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16232                ) {
16233                    $isReservedCanSuddenLesson = true;
16234                }
16235    
16236                // if failed settlement -> paid or corporate individual (standard/premium)
16237                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
16238                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
16239                // if free 
16240                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
16241                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
16242                // if free (trial not yet conducted)
16243                } elseif ($this->userMembershipType == 13) {
16244                    $userNotEligible = 10;
16245                    $use7DaysTrialModal = true;
16246                // if corporate company settlement failed -> standard/premium or
16247                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
16248                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
16249                }
16250
16251                // NJ-48797
16252                $avatarParentFlg = isset($commonTeacher2['Teacher']['avatar_parent_flg']) && $commonTeacher2['Teacher']['avatar_parent_flg'] == 1;
16253
16254                if (!$avatarParentFlg) {
16255                    $getParentAvatarTeacher = $this->Teacher->find('first', array(
16256                        'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
16257                        'conditions' => array(
16258                            'Teacher.id' => $commonTeacher2['Teacher']['avatar_id'],
16259                            'Teacher.avatar_parent_flg' => 1
16260                        ),
16261                        'recursive' => -1
16262                    ));
16263                } else {
16264                    $getParentAvatarTeacher = $commonTeacher2;
16265                }
16266                
16267                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
16268                $membershipTypeReservationOnly = false;
16269    
16270                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
16271                    $membershipTypeReservationOnly = true;
16272                }
16273    
16274                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
16275                $membershipTypeBlueBtn = false;
16276    
16277                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
16278                    $teacherStatusColor = 'wait';
16279                    $membershipTypeBlueBtn = true;
16280                }
16281    
16282                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
16283    
16284                if(!$isGuestViewer && $liveLessonFlg) {
16285                    $reservedLessonData = $api['reservedLessonData'];
16286    
16287                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
16288                        $liveStatus = 0;
16289                    } else {
16290                        //- if lesson started
16291                        if (
16292                            !is_null($api['LessonOnair']['connect_id']) &&
16293                            !is_null($api['LessonOnair']['user_id'])
16294                        ) {
16295                            if ($api['LessonOnair']['user_id'] == $studentId) {
16296                                $liveStatus = 4;
16297                            } else {
16298                                //- check live status
16299                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
16300                                    'user_id' => $studentId,
16301                                    'chat_hash' => $api['LessonOnair']['chat_hash']
16302                                ]);
16303    
16304                                //-- override status to watch
16305                                if ($liveStatus == 1) {
16306                                    $liveStatus = 2; //view live
16307                                }
16308                            }
16309                        } else {
16310                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
16311                                'teacher_id' => $teacherId
16312                            ]);
16313    
16314                            //-has reservation
16315                            if ($waitingReservationLive) {
16316                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
16317                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
16318                                } else {
16319                                    $liveStatus = 1; //live will start
16320                                }
16321                            }
16322                        }
16323                    }
16324                }
16325    
16326                if(!$this->isStudySapuriTosUser) {
16327                    $teacherStudentConnection = $api['teacherStudentConnection'];        
16328                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
16329                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
16330                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
16331                            'teacher_id' => $teacherId,
16332                            'teacherStudentData' => $teacherStudentData,
16333                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
16334                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
16335                            'nickname' => $user['User']['nickname'],
16336                            'admin_flg' => $userAdminFlag,
16337                            'isReserved' => $isReserved,
16338                            'type' => 1
16339                        ));
16340                    }
16341                }
16342    
16343                // check if busy
16344                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
16345                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
16346                        $isBusy = true;
16347                    }
16348                }
16349    
16350                // NC-5409 : Corporate Limited Plan
16351                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
16352    
16353                    // check if legible
16354                    if (
16355                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
16356                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16357                            $userDuplicateLesson || 
16358                            $unsupportedBrowser ||
16359                            $lessonOnOther
16360                        ) &&
16361                        $studentId
16362                    ) {
16363                        $userNotEligible = 1;
16364                    }
16365    
16366                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
16367    
16368                    $corpLightCondition1 = (
16369                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
16370                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16371                        $userDuplicateLesson ||
16372                        $unsupportedBrowser ||
16373                        $lessonOnOther
16374                    );
16375                    // check if legible
16376                    if ( $corpLightCondition1 && $studentId) {
16377                        $userNotEligible = 2;
16378                    }
16379                } elseif (
16380                    (
16381                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
16382                        $commonTeacher2['Teacher']['native_speaker_flg']
16383                    ) &&
16384                    (
16385                        $user['User']['native_option'] == null ||
16386                        $user['User']['native_option'] == 0
16387                    ) &&
16388                    !$isReserved &&
16389                    !$tmp->live_lesson_flg &&
16390                    !$this->isStudySapuriTosUser
16391                ) {
16392                    $userNotEligible = 3;
16393                    $showNativeSpeakerWarning = true;
16394                } elseif ( // NJ-48797
16395                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
16396                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
16397                    !$isReserved &&
16398                    !$tmp->live_lesson_flg &&
16399                    !$this->isStudySapuriTosUser
16400                ) {
16401                    $showNativeSpeakerWarning = true;
16402                    $userNotEligible = 4;
16403                } else {
16404                    // check if legible
16405                    if ((
16406                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
16407                        $userDuplicateLesson || 
16408                        $unsupportedBrowser || 
16409                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
16410                        $lessonOnOther
16411                    ) && $studentId) {
16412                        $userNotEligible = 5;
16413                    }
16414                }
16415    
16416                # ~no sudden lesson for sapuri toS user
16417                if ($this->isStudySapuriTosUser && !$isReserved) {
16418                    $userNotEligible = 6;
16419                }
16420    
16421                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
16422    
16423                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
16424                    # disable the lesson button for lite plan if it is not reserved lesson
16425                    $userNotEligible = 7;
16426    
16427                    # add if reserve is still ongoing 
16428                    if($isReserved) {
16429                        $userNotEligible = false;
16430                    }
16431                }
16432    
16433            }            
16434    
16435            switch($stateButton) {
16436                case 2: //proceed_to_the_lesson_immediately
16437                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
16438                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
16439                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
16440                    ) {
16441                        $stateButton = 5; //busy
16442                    }
16443                    break;
16444                case 3: // go to reserved lesson
16445                case 32: // dummy lesson
16446                    $teacherStatusColor = 'wait';
16447                    break;
16448                case 15: //other
16449                case 5: //busy
16450                    if(
16451                        ($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') &&
16452                        $membershipTypeReservationOnly
16453                    ) {
16454                        $stateButton = 6;
16455                        $lessonStartBtnText = __d('waiting','予約専用です');
16456                    }
16457                    $teacherStatusColor = 'lesson';
16458    
16459                    break;
16460                default:
16461            }
16462
16463            $studentRemainingSecondsDelay = 0;
16464            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
16465    
16466            // show orange button
16467            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
16468
16469            if (
16470                $canLessonTextbook &&             # - can lesson with the textbook
16471                !$textbookForReservationOnly && # - textbook not for reserve only
16472                !$unsupportedBrowser &&         # - supported browser
16473                $userDuplicateLesson &&         # - has lesson with other teacher
16474                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16475                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16476                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16477            ) {
16478                $canMidwayLesson = true;
16479            }
16480        } //end !$isGuestViewer
16481    
16482        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
16483        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
16484        $showLoader = $isGuestViewer ? true : false;    
16485        $suddenLessonFlg = false;
16486        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
16487    
16488        if (
16489            $isReserved && 
16490            (
16491                $this->isStudySapuriUser || 
16492                $this->isStudySapuriTosUser || 
16493                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
16494            )
16495        ) {
16496            $canDoLive = false;
16497        }
16498    
16499        if(
16500            !$isViewer && 
16501            !$isEmergencyLesson && 
16502            !$isReservedCanSuddenLesson & 
16503            !$canMidwayLesson &&
16504            !$isReserved
16505        ) {
16506            if($teacherStatusColor == 'wait') {
16507                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
16508                    $isBusy = true;
16509                }
16510    
16511                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
16512                    $suddenLessonFlg = true;
16513                }
16514            }
16515    
16516            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
16517                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
16518                    
16519                    if($membershipTypeBlueBtn) {
16520                        $suddenLessonFlg = true;
16521                        $teacherStatusColor = 'wait';
16522                    }
16523                }
16524            }
16525        }
16526    
16527        $canEmergencyLesson = false;
16528        $emergencyBreakTime = ['status' => false];        
16529        $currentMinutes = date("i");
16530        $currentHour = date("H");        
16531
16532        if ($isEmergencyLesson) {
16533            if ($this->isStudySapuriTosUser) {
16534                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
16535                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
16536                $queryCondition['fields'][] = "(
16537                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
16538                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
16539                    ) as can_emergency_lesson";
16540                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
16541                    as student_no_next_reservation";
16542            }
16543
16544            $commonTeacherStatusParams = array(
16545                'page_display' => 'listTeacher',
16546                'query_conditions' => $queryCondition
16547            );
16548            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16549            
16550            if (
16551                $this->isStudySapuriTosUser &&
16552                !$isReserved &&
16553                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
16554                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
16555                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
16556                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
16557            ) {
16558                $canEmergencyLesson = true;
16559            }
16560
16561            # ~if emergency lesson break time
16562            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
16563                $canEmergencyLesson = false;
16564                $emergencyBreakTime['status'] = true;
16565                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
16566                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
16567            }
16568        }
16569    
16570        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
16571    
16572        // lesson alert
16573        $lessonAlertMsg = [];
16574        $lessonAlertStatus = '';
16575    
16576        // if emergency lesson break time
16577        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
16578            $lessonAlertMsg = [
16579                ['text' => __d('waiting','しばらくお待ちください。')],
16580                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
16581                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
16582            ];
16583            $lessonAlertStatus = 'emergency_lesson_break_time';
16584        }
16585    
16586        if (
16587            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
16588            !$isReserved &&
16589            !$isAvatar
16590        ) {
16591            $lessonAlertMsg = [
16592                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
16593                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
16594                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
16595            ];
16596            $lessonAlertStatus = 'exceed_daily_limit';
16597        }
16598    
16599        // set localize url
16600        if (
16601            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
16602            $get['la'] != Configure::read('default.user_language')
16603        ) {
16604            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
16605        } else {
16606            $localizeUrl = myTools::getUrl();
16607        }
16608    
16609        $displayFamilyAlert = false;
16610        if (
16611            isset($this->sharedUserData['User']['parent_id']) &&
16612            !is_null($this->sharedUserData['User']['parent_id'])
16613        ) {
16614            $parent = $this->User->find('first', array(
16615                'fields' => array(
16616                    'User.id',
16617                    'User.hash16',
16618                    'User.charge_flg'
16619                ),
16620                'conditions' => array(
16621                    'User.id' => $this->sharedUserData['User']['parent_id']
16622                ),
16623                'recursive' => -1
16624            ));
16625    
16626            if ($parent && $parent['User']['charge_flg'] != 1) {
16627                $displayFamilyAlert = true;
16628            }
16629        }
16630    
16631        $device = false;
16632        if (strpos($ua, 'Silk') !== false) {
16633            $device = 'kindle';
16634        } else if (strpos($ua, 'Android') !== false) {
16635            $device = 'andriod';
16636        } else if (strpos($ua, 'iPhone') !== false) {
16637            $device = 'ios';
16638        } else if (strpos($ua, 'iPad') !== false) {
16639            $device = 'ios';
16640        } else if (strpos($ua, 'iPod') !== false) {
16641            $device = 'ios';
16642        } else {
16643            $device = 'pc';
16644        }
16645    
16646        $corporateIndividualUser = false;
16647        $corporateTypes = Configure::read('corporate_type_arr');
16648        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16649        if (isset($user['User']['corporate_id'])) {
16650            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
16651            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
16652        }
16653    
16654        if (
16655            !$this->isStudySapuriUser &&
16656            $lessonType == Configure::read('lesson.type.reservation') &&
16657            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
16658        ) {
16659            $isReservedCanLessonViewing = true;
16660        }
16661    
16662        $showTakeBusinessTestModal = false;
16663        if (isset($user['User']['corporate_id'])) {
16664            $showTakeBusinessTestModal = false;
16665            $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
16666            $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
16667            $corporateUserDate = time();
16668            $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
16669    
16670            if (
16671                ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
16672                !$isReserved &&
16673                (
16674                    $corporateUserDate >= $twentyPlusDayOfTheMonth ||
16675                    (
16676                        $userAdminFlag == 1 ||
16677                        (
16678                            isset($user["User"]["nickname"]) &&
16679                            strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
16680                        )
16681                    )
16682                )
16683            ) {
16684                $showTakeBusinessTestModal = true;
16685            }
16686        }        
16687    
16688        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
16689        $button = $buttonStates[$stateButton];
16690    
16691        if(!$isGuestViewer) {
16692            $json = array_merge($json, [
16693                'button' => $button,
16694                'canDoLive' => $canDoLive,
16695                'canEmergencyLesson' => $canEmergencyLesson,
16696                'canLesson' => $canLesson,
16697                'canLessonTextbook' => $canLessonTextbook,
16698                'canMidwayLesson' => $canMidwayLesson,
16699                'checkBadge' => $checkBadge,
16700                'commonTeacher2' => $commonTeacher2,
16701                'corporateIndividualUser' => $corporateIndividualUser,
16702                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
16703                'corporateType' => $corporateType,
16704                'corporateUserFlg' => $corporateUserFlg,
16705                'corpLightCondition' => $corpLightCondition1,
16706                'device' => $device,
16707                'displayFamilyAlert' => $displayFamilyAlert,
16708                'dummyLessonRoom' => $hasLessonBeforeActualTime,
16709                'emergencyBreakTime' => $emergencyBreakTime,
16710                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
16711                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
16712                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
16713                'isAvatar' => $isAvatar,
16714                'isBusy' => $isBusy,
16715                'isEmergencyLesson' => $isEmergencyLesson,
16716                'isNormalLitePlanUser' => $isNormalLitePlanUser,
16717                'isRedLamp' => $isRedLamp,
16718                'isReserved' => $isReserved,
16719                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
16720                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
16721                'isStudySapuriTosUser' => $this->isStudySapuriUser,
16722                'isViewer' => $isViewer,
16723                'lessonAlertMsg' => $lessonAlertMsg,
16724                'lessonAlertStatus' => $lessonAlertStatus,
16725                'lessonOnOther' => $lessonOnOther,
16726                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
16727                'lessonType' => $lessonType,
16728                'liveData' => $liveData,
16729                'liveLessonFlg' => $liveLessonFlg ?? null,
16730                'liveLessonText' => $liveLessonText,
16731                'liveStatus' => $liveStatus,
16732                'localizeUrl' => $localizeUrl,
16733                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
16734                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
16735                'oOnair' => $oOnair,
16736                'uOnair' => $uOnair,
16737                'onGoingLesson' => $onGoingLesson,
16738                'paymentPlanId' => $user['User']['payment_plan_id'],
16739                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
16740                'redirectPlanUrl' => $redirectPlanUrl,
16741                'reservedLessonData' => $reservedLessonData,
16742                'sapuriCoin' => $sapuriCoin,
16743                'scheduleReservationData' => $scheduleReservationData,
16744                'showLoader' => $showLoader,
16745                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
16746                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
16747                'stateButton' => $stateButton,
16748                'stateButtonApi' => $api['teacher']['state_button'],
16749                'studentId' => $studentId,
16750                'suddenLessonFlg' => $suddenLessonFlg,
16751                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
16752                'teacherLeaveNotice' => $teacherLeaveNotice,
16753                'teacherStatus' => $teacherStatus,
16754                'teacherStatusApi' => $_teacherStatus,
16755                'teacherStatusColor' => $teacherStatusColor,
16756                'textbookForReservationOnly' => $textbookForReservationOnly,
16757                'unverifiedSMS' => $stateButton == 7 ? true : false,
16758                'unsupportedBrowser' => $unsupportedBrowser,
16759                'use7DaysTrialModal' => $use7DaysTrialModal,
16760                'userAdminFlag' => $userAdminFlag,
16761                'userDoubleCheckFlag' => $userDoubleCheckFlag,
16762                'userDuplicateLesson' => $userDuplicateLesson,
16763                'userFailFlag' => $userFailFlag,
16764                'userMembershipType' => $this->userMembershipType,
16765                'userNativeOption' => $user['User']['native_option'],
16766                'userNotEligible' => $userNotEligible
16767            ]);
16768
16769            if($membershipTypeReservationOnly) {
16770                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
16771            }
16772
16773            if($suddenLessonFlg) {
16774                if($use7DaysTrialModal) {
16775                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
16776                } else if (!empty(trim($redirectPlanUrl))) {
16777                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
16778                } else if ($showNativeSpeakerWarning) {
16779                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
16780                } else if ($unsupportedBrowser) {
16781                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
16782                } else if (!$canLessonTextbook) {
16783                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
16784                } else if (!empty($teacherLeaveNotice)) {
16785                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
16786                }
16787
16788                if(!empty($json['suddenLessonStatus'])) {
16789                    $json['validateSuddenLessonFlg'] = false;
16790                } else {
16791                    $json['validateSuddenLessonFlg'] = true;
16792                }
16793            }
16794            
16795        } else if ($isViewer || $isGuestViewer) {
16796            $json = array_merge($json, [
16797                'canLesson' => $canLesson
16798            ]);
16799        }
16800
16801        if($env != 'PRODUCTION') {
16802            $json['api'] = $api;
16803            $json['commonTeacher2'] = $commonTeacher2;
16804            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
16805            $json['tmpLessonOnAir'] = $tmp;
16806        }
16807    
16808        return json_encode($json);
16809    }
16810
16811    public function checkLessonStartButtonCounselor() {
16812        $this->autoRender = false;
16813        $this->layout = false;
16814        $userId = $this->Auth->user('id');
16815
16816        // if api token is not set
16817        if (empty($this->sharedUserData['User']['api_token'])) {
16818            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16819            $this->Session->write('Auth.User.api_token', $userApiToken);
16820        }
16821
16822        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16823        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16824        $TeachersCounselorDetailController->params = [
16825            'nc_terminal_type' => 1, // pc
16826            'users_api_token' => $this->Auth->user('api_token'),
16827            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16828            'device_type' => 2
16829        ];
16830        
16831        $data = json_decode($TeachersCounselorDetailController->counselorDetail(), true);
16832        $teacherId = $data['available_teacher'] ?? '';
16833        $status = $data['teacher']['status'] ?? '';
16834        $exceedDailyLimit = $data['exceed_daily_limit'] ? 1 : 0;
16835
16836        if ($status == 3) {
16837            $status = 2;
16838        } elseif ($status == 4) {
16839            $status = 3;
16840        }
16841
16842        return json_encode(
16843            array(
16844                'user_id' => $userId,
16845                'teacher_id' => $teacherId,
16846                'status' => $status,
16847                'exceed_daily_limit' => $exceedDailyLimit        
16848            )
16849        );
16850        
16851    }
16852
16853    public function checkLessonStartButtonCS() {
16854        $this->autoRender = false;
16855        $this->layout = false;
16856        $userId = $this->Auth->user('id');
16857        
16858        // if api token is not set
16859        if (empty($this->sharedUserData['User']['api_token'])) {
16860            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16861            $this->Session->write('Auth.User.api_token', $userApiToken);
16862        }
16863
16864        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16865        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16866        $TeachersCounselorDetailController->params = [
16867            'nc_terminal_type' => 1, // pc
16868            'users_api_token' => $this->Auth->user('api_token'),
16869            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16870            'device_type' => 2
16871        ];
16872
16873        if($this->userMembershipType === 12) {
16874            $csParams = array(
16875                'user_id' => $userId,
16876                'user_data' => $this->sharedUserData['User'],
16877                'customer_support_flg' => 1
16878            );
16879
16880            $data = json_decode( $this->LessonOnair->checkCounselorTeacherButtonStatus($csParams), true);
16881            $status = $data['res'] ?? '';
16882        } else {
16883            $data = json_decode($TeachersCounselorDetailController->customerSupportDetail(), true);
16884            $status = $data['teacher']['status'] ?? '';
16885        }
16886
16887        $teacherId = $data['available_teacher'] ?? '';
16888        $exceedDailyLimit = !empty($data['exceed_daily_limit']) ? 1 : 0;
16889
16890        if ($status == 3) {
16891            $status = 2;
16892        } elseif ($status == 4) {
16893            $status = 3;
16894        }
16895
16896        // Check if user exceeds daily limit for customer support lessons
16897        if ($userId) {
16898            $csList = $this->Teacher->getCustomerSupportTeachers();
16899            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, $csList['customerSupportId']);
16900            if ($csExceedLimitCheck) {
16901                $exceedDailyLimit = 1;
16902                $status = 0;
16903            }
16904        }
16905
16906        return json_encode([
16907            'user_id' => $userId,
16908            'teacher_id' => $teacherId,
16909            'status' => $status,
16910            'exceed_daily_limit' => $exceedDailyLimit,
16911            'membership_type' => $this->userMembershipType
16912        ]);
16913    }
16914    public function updateLessonSystemTrouble() {
16915        $this->autoRender = false;
16916        $this->layout = false;
16917        $troubleResponse = false;
16918
16919        if ($this->request->is('ajax')) {
16920            $chatHash = $this->request->data['chat_hash'] ?? '';
16921            $status = $this->request->data['status'] ?? 0;
16922            $teacherID = $this->request->data['teacher_id'] ?? null;
16923            $storeMemcache = $this->request->data['store_memcache'] ?? 0;
16924
16925            if ($storeMemcache && $chatHash) {
16926                $memcached = new myMemcached();
16927                // $memcached->set(array(
16928                //     'key' => 'hide_connection_modal_flg_'.$teacherID.'-'.$chatHash,
16929                //     'value' => 1,
16930                //     'expire' => 86400 //-- 24hrs
16931                // ));
16932                $troubleResponse = true;
16933                $this->log("successfully added memcache");
16934            }
16935        }
16936
16937        return json_encode(array('result' => $troubleResponse));
16938    }
16939    
16940    public function setAppreciationModalFinish(){
16941        $this->autoRender = false;
16942        $this->layout = false;
16943
16944        if(empty($this->request->data['chat_hash'])){
16945            return false;
16946        }
16947
16948        $chat_hash = $this->request->data['chat_hash'];
16949
16950        if (!class_exists('myMemcached')) {
16951            App::uses('myMemcached', 'Lib');
16952        }
16953        $memcached = new myMemcached();
16954        $memcached->set(array(
16955            'key' => "appreciation_done_".$chat_hash,
16956            'value' => 1,
16957            'expire' => 86400 // 1 day
16958        ));
16959
16960        return true;
16961    }
16962}